The following code only works if you uncomment the line
virtual void FuncA() { ImplA::FuncA(); }
in class ImplB, otherwise I get compiler error:
cannot instantiate abstract class ... FuncA(void)' : is abstract
Question is why doesn't it get the implement for FuncA() from the inherited ImplA?
class InterfaceA {
public:
virtual void FuncA()=0;
};
class InterfaceB : public InterfaceA {
public:
virtual void FuncB()=0;
};
class ImplA : public InterfaceA {
public:
virtual void FuncA() { printf("FuncA()\n"); }
};
class ImplB : public ImplA, public InterfaceB {
public:
// virtual void FuncA() { ImplA::FuncA(); }
virtual void FuncB() { printf("FuncB()\n"); }
};
{
ImplB *b = new ImplB();
InterfaceA *A= b;
A->FuncA();
InterfaceB *B= b;
B->FuncB();
B->FuncA();
}
You've hit an instance of the "diamond" problem in multiple inheritance.
You'll need to use "virtual" inheritance (which amounts to adding the keyword virtual when inheriting)
The problem is that ImplB has two paths to the base class InterfaceA. However, your intention is that the interfaces do not provide any implementation. Thus, you need to indicate this to the compiler, so it can unify the pure virtual functions.
For a much better explanation:
http://www.cprogramming.com/tutorial/virtual_inheritance.html
I've modified your code to add virtual when you inherit from interfaces. Now it compiles, even with the line commented. Also note, I think you are missing virtual destructors, so you'll have some other problems down the line. This code compiles, without uncommenting FuncA.
#include <cstdio>
class InterfaceA {
public:
virtual void FuncA()=0;
};
class InterfaceB : public virtual InterfaceA {
public:
virtual void FuncB()=0;
};
class ImplA : public virtual InterfaceA {
public:
virtual void FuncA() { printf("FuncA()\n"); }
};
class ImplB : public ImplA, public virtual InterfaceB {
public:
// virtual void FuncA() { ImplA::FuncA(); }
virtual void FuncB() { printf("FuncB()\n"); }
};
int main()
{
ImplB *b = new ImplB();
InterfaceA *A= b;
A->FuncA();
InterfaceB *B= b;
B->FuncB();
B->FuncA();
}
Multiple inheritance isn't "mixins"
You can inherit from multiple classes that have methods with the same name but that doesn't make them the same.
The thing that inherits from a virtual class must implement the pure virtual functions of its parents.
If the method names weren't scoped, you could end up with combinations of parent classes that were mutually exclusive to inherit from because the implementations of the method with the shared name wouldn't be compatible.
I am a bit surprised that putting using ImplA::FuncA; in ImplB doesn't solve it, though: https://gcc.godbolt.org/
Related
I want to provide a stable API for a library I've written by providing a set of pure abstract classes.
Consider the following class hierarchy:
//Note: Destructors left out for readability
struct IBase{
virtual void something() = 0;
}
struct IDerivedA : public IBase{
virtual void another() = 0;
}
struct IDerivedB : public IBase{
virtual void another(int a) = 0;
}
There will be multiple implementations for these interfaces. To write an implementation, I would do:
struct Base : public IBase{
int x; //x is required to implement something()
virtual void something();
}
struct DerivedA : public IDerivedA, public Base{
virtual void another();
}
struct DerivedB : public IDerivedB, public Base{
virtual void another(int a);
}
This leads to the dreaded diamond problem, for which I see the following solutions:
Virtually inherit IBase in both IDerivedA and IDerivedB and just use multiple inheritance
Don't use Base at all and instead forward the calls to a helper class to avoid code duplication
Something like:
struct Base{
int x; //x is required to implement somethingImpl()
void somethingImpl();
}
struct DerivedA : public IDerivedA{
virtual void something(){ b.somethingImpl(); };
virtual void another();
private:
Base b;
}
struct DerivedB : public IDerivedB{
virtual void something(){ b.somethingImpl(); };
virtual void another(int a);
private:
Base b;
}
In case of 1), virtual inheritance would be required every time I use inheritance in the API layer.
In case of 2), I would need to wrap Base for every implementation class, which leads to code bloat.
I believe that there might be something fundamentally wrong in the design. Is there a general best practice for this specific case?
I was wondering what was the best way to achieve code reuse by inheritance in a COM application.
The Problem
It came to my understanding that the virtual inheritance model of C++ cannot by used in a COM environment because it is not language independent.
In pure C++ a class hierarchy could look something like the following:
interface IBase {
virtual void BaseMethod() = 0;
};
interface IDerived : virtual IBase {
virtual void DerivedMethod() = 0;
};
class CBase : public virtual IBase {
public:
virtual void BaseMethod() override { /* Do something */ }
};
class CDerived : public IDerived, public CBase {
public:
virtual void DerivedMethod() override { /* Do something */ }
};
This results in the following hierarchy:
IDerived and CBase both inherit virtually from IBase.
Since virtual inheritance is not available in COM, the class hierarchy would rather look something like this:
interface IBase {
virtual void BaseMethod() = 0;
};
interface IDerived : IBase {
virtual void DerivedMethod() = 0;
};
class CBase : public IBase {
public:
virtual void BaseMethod() override { /* Do something */ }
};
class CDerived : public IDerived, public CBase {
public:
virtual void DerivedMethod() override { /* Do something */ }
};
This results in the following hierarchy:
At first glance, there seems to be a problem with the ambiguity of IBase. This can be easily resolved by implementing the IUnknown::QueryInterface method.
The real problem is, how can CDerived inherit the implemented methods of IBase from CBase, namely CBase::BaseMethod?
In the case of virtual inheritance, CBase::BaseMethod can be inherited by dominance, but without virtual inheritance this cannot happen: In CDerived, the method CBase::IBase::BaseMethod is defined, however the method IDerived::IBase::BaseMethod is not, resulting in the class CBase still being abstract and not thus not eligible for instantiation.
One way, to resolve this would be to override the method BaseMethod in CDerived once again:
class CDerived : public IDerived, public CBase {
public:
virtual void BaseMethod() override { CBase::BaseMethod(); }
virtual void DerivedMethod() override { /* Do something */ }
};
Does this have any performance implications? Is there a better way of achieving what I want? Doesn't the repeated override of the function in CDerived defeat the whole idea of inheritance?
ATL widely uses a technique that goes like this:
template <typename Itf>
class IBaseImpl : public Itf {
public:
void BaseMethod() override;
};
class CBase : public IBaseImpl<IBase> {};
class CDerived : public IBaseImpl<IDerived> {
public:
void DerivedMethod() override;
};
Now you have straight-line inheritance: IBase <- IDerived <- IBaseImpl<IDerived> <- CDerived.
Question
Why not to try virtual inheritance if it seems to solve my diamond inheritance problem below?
Briefing:
While learning C++, I came with some compiler errors for the following code:
#include <stdlib.h>
#include <iostream>
class IFoo{
public:
virtual void Hello() = 0;
};
class Foo : public IFoo{
public:
void Hello()
{
printf("Hello");
}
};
class IBar : public IFoo{
public:
virtual void HelloWorld() = 0;
};
class Bar : public IBar, public Foo{
public:
void HelloWorld()
{
Hello();
printf("World");
}
};
int main()
{
Bar b;
b.HelloWorld();
system("pause");
return 0;
}
I want Bar to implement abstract class IBar which has IFoo as a base class but then I want all the implementation of IFoo provided by Bar's second base class Foo.
I get 2 compiler errors (GCC 4.9.2): One related to ambiguities and another one about missing implementations for abstract class IFoo.
Then I found this question and got to meet the concept of virtual inheritance, which lead me to this page. Following the tutorial, I added virtual inheritance and all problems were gone:
class Foo : public virtual IFoo{...
class IBar : public virtual IFoo{...
But a user in the question suggest not to try virtual inheritance. Hence my question.
Your class
Bar
must override
Hello
otherwise class Bar also becomes purely abstract, because
Hello
is inherited all the way from
IFoo.
Whenever a class inherits an abtract base class it must implement all of the base class' pure virtual functions, otherwise the derived class itself also becomes abstract.
class Base{
public:
virtual void foo() = 0;
};
// this class is abstract, it doesn't implement Base::foo
class Derived1 : public Base{
public:
void fooDerived() {}
};
// this class is not abstract, it implements Base::foo
class Derived2 : public Base{
public:
void foo() {}
};
As suggested in another answer, in C++11 you can declare the function using the override keyword, which ensures that the function overrides a virtual function. Like this:
// this class is not abstract, it implements Base::foo
class Derived2 : public Base{
public:
void foo() override {}
};
Virtual inheritance solves another problem, the problem of ambiguity when inheriting from more than one base class which declares identical functions or members.
Your Hello() call in Bar::HelloWorld() is ambiguous. The compiler can't tell if you are trying to call Hello() from IBar or Foo. You can call Foo::Hello() or IBar::Hello() in it's place. That being said, your inheritance structure doesn't really make sense.
Your Bar class also needs to override Hello that it inherits from IBar.
If you have c++11, it would be a good idea to mark the virtual functions you are overriding with the override keyword:
#include <stdlib.h>
#include <iostream>
class IFoo{
public:
virtual void Hello() = 0;
};
class Foo : public IFoo{
public:
virtual void Hello() override
{
printf("Hello");
}
};
class IBar : public IFoo{
public:
virtual void HelloWorld() = 0;
};
class Bar : public IBar, public Foo{
public:
virtual void HelloWorld() override
{
Foo::Hello();
printf("World");
}
void Hello() override {}
};
int main()
{
Bar b;
b.HelloWorld();
system("pause");
return 0;
}
To answer your question on virtual inheritance, you could easily change your inheritance structure to something that still works that avoids a diamond pattern. The diamond pattern is rarely needed and is usually avoidable:
#include <stdlib.h>
#include <iostream>
class IFoo{
public:
virtual void Hello() = 0;
};
class Foo : public IFoo{
public:
virtual void Hello() override
{
printf("Hello");
}
};
class IBar {
public:
virtual void World() = 0;
};
class Bar : public IBar{
public:
virtual void World() override
{
printf("World");
}
};
class FooBar : public Foo, public Bar
{
public:
virtual void HelloWorld()
{
Hello();
World();
}
};
int main()
{
FooBar b;
b.HelloWorld();
system("pause");
return 0;
}
Say I have an interface hierarchy :
class A
{
virtual void commonFunc() = 0;
};
class B1 : public A
{
virtual void b1SpecificFunc() = 0;
};
class B2 : public A
{
virtual void b2SpecificFunc() = 0;
};
Interface A only exist to avoid duplicating the commonFunc() function.
Now if I want to implement this in order to have 2 instanciatable classes ImplB1 and ImplB2 i could do :
class ImplA
{
virtual void commonFunc();
};
class ImplB1 : public ImplA
{
virtual void b1SpecificFunc();
};
class ImplB2 : public ImplA
{
virtual void b2SpecificFunc();
};
The problem with this is that it makes ImplA instanciatable, which I don't want to. I only want ImplB1 and ImplB2 to be instanciatable, because ImplA is something asbtract that only exist to have the implementation of the common function in common.
How could i design this please ? Thank you.
Interface A only exist to avoid duplicating the commonFunc() function.
You certainly mean to avoid duplicating its declaration, don't you?
class ImplA
{
virtual void commonFunc();
};
This should probably be:
class ImplA : public A
{
virtual void commonFunc();
};
And I guess the point is that ImplA actually has an implementation of commonFunc. So for the sake of this answer's brevity, let's put it into the class definition:
class ImplA : public A
{
virtual void commonFunc() {} // implementation
};
The problem with this is that it makes ImplA instanciatable.
Just make ImplA's destructor pure virtual:
class ImplA : public A
{
public:
virtual ~ImplA() = 0 {}
private:
virtual void commonFunc() {}
};
This will prevent instantiation even inside of derived classes' functions. For example, the following will create a compiler error:
class ImplB1 : public ImplA
{
public:
virtual void b1SpecificFunc()
{
ImplA a; // error, cannot instantiate abstract class
}
};
In fact, you will not even be able to instantiate the class in its own functions:
class ImplA : public A
{
public:
virtual ~ImplA() = 0 {}
private:
virtual void commonFunc()
{
ImplA a; // error, cannot instantiate abstract class
}
};
But seriously, this all seems pretty over-engineered. Perhaps what you really need is to make commonFunc a non-virtual protected function of A, which derived classes can then call if they need to.
Or perhaps commonFunc can just be a free-standing utility function?
You can do the following. Also, here is a SO question/answer about this.
Note: While I'm answering the question that you can do this I'm not asserting it's what you should do.
Code
#include <iostream>
class A
{
public:
virtual void commonFunc() = 0;
};
void A::commonFunc() // Pure virtual but implemented anyway
{
// Derived classes can explicitly opt-in to this implementation
std::cout << "A::commonFunc()\n";
}
class B1 : public A
{
public:
virtual void b1SpecificFunc() = 0;
};
class B2 : public A
{
virtual void b2SpecificFunc() = 0;
};
class ImplB1 : public B1
{
public:
// This function must be implemented because its declared pure virtual
virtual void commonFunc()
{
// Can override the behavior if desired...
A::commonFunc(); // Explicitly use default implementation
}
virtual void b1SpecificFunc()
{
std::cout << "b1SpecificFunc()\n";
}
};
class ImplB2 : public B2
{
public:
// This function must be implemented because its declared pure virtual
virtual void commonFunc()
{
// Can override the behavior if desired...
A::commonFunc(); // Explicitly use default implementation
}
virtual void b2SpecificFunc()
{
std::cout << "b2SpecificFunc()\n";
}
};
int main()
{
//A a; // Won't compile (as expected/desired)
ImplB1 b1;
ImplB2 b2;
b1.commonFunc();
b1.b1SpecificFunc();
b2.commonFunc();
b2.b2SpecificFunc();
return 0;
}
Output
A::commonFunc()
b1SpecificFunc()
A::commonFunc()
b2SpecificFunc()
I am trying to figure out how to arrange some classes. This is what I've got so far ...
The top of the inheritance hierarchy is (naturally) T:
(T.h)
namespace foo
{
class T
{
public:
virtual void method1(std::string a_parameter) = 0;
virtual void method2() = 0;
};
}
I have two sub-classes of T with some additional methods - here are
the header files:
(A.h)
namespace foo
{
class A : public T
{
public:
virtual ~A() {};
virtual void method3() = 0;
//and a factory function
static A* gimmeAnAyy();
};
}
(B.h)
namespace foo
{
class B : public T
{
public:
virtual ~B() {};
virtual void method4() = 0;
//and a factory function
static B* gimmeABee();
};
}
The implementation classes are in the respective .cpp files:
(A.cpp)
namespace foo
{
class AImpl : public A
{
public:
A(std::string member_data) : m_member_data(member_data) {};
~A() {};
void method3()
{
//something really important, can't think of it right now ;-)
};
private:
std::string m_member_data;
};
A* A::gimmeAnAyy()
{
return new AImpl("this is an impl of A");
};
}
(B.cpp)
namespace foo
{
class BImpl : public B
{
public:
B(std::string other_data) : m_other_data(other_data) {};
~B() {};
void method4()
{
//something really important, can't think of it right now ;-)
};
private:
std::string m_other_data;
};
B* B::gimmeABee()
{
return new BImpl("this is an imll of B");
};
}
Now the compiler complains - rightly so - about the virtual functions
method1() and method2() that I haven't implemented in AImpl and BImpl.
What I want is a TImpl class that both AImpl and BImpl can inherit from
so that I don't have to implement method1() and method2() in two different .cpp files.
Is it possible? Am I out to lunch? Am I asking too many rhetorical questions for a StackExchange post?
Thanks in advance,
Mike
Yeah, it is possible. Common practice is to use the following snippet:
template<typename Interface>
class TImpl : public Interface
{
public:
virtual void method1(std::string a_parameter) { /* implementation */ }
virtual void method2() { /* implementation */ }
};
And then inherit from it as follows:
class Aimpl : public TImpl<A>
{
public:
virtual void method3() { /* implementation */ }
};
class Bimpl : public Timpl<B>
{
public:
virtual void method4() { /* implementation */ }
};
You can put implementation of Timpl in cpp file, but then you have to explicitly instantiate it for every possible interface. This is done as follows in the cpp:
template<typename Interface>
void Timpl<Interface>::method1(std::string a_parameter)
{
/* implementation */
}
template<typename Interface>
void Timpl<Interface>::method2()
{
/* implementation */
}
template class Timpl<A>;
template class Timpl<B>;
Do not make method1 and method2 pure virtual functions. Give them an implementation!
i.e.
declare
class T
{
public:
virtual void method1(std::string a_parameter);
virtual void method2();
};
Define:
void T::method1(std::string a_parameter) { // Could use const/reference here perhaps
....
}
etc...
It seems your problem is the wrong believe that it is better to have only pure virtual functions in your base class! Just get over it and provide a default implementation in T. Although there are religious believes that is bad, there isn't any technical reason not to have it. Insisting in having only pure virtual functions in base classes is like insisting in all music having to be 12-tone music!
since both of the son classes (A & B) don't have (method1, method2) then you don't have to use the virtual. you can easily provide a default implementation in the base class and then invoke and use these methods through the inheritance chain since the inheritance type here is public.
In the A and B classes declaration, the methods 3 and 4 are pure virtual, so in the definition file you shouldn't gives an implementation of them. In my understand A and B are leading the implementation of the T methods and their own virtual methods to other concrete classes who inherit from them. If you thing that A and B are concrete classes, put away the "= 0" from the following lines:
class A : public T
{
public:
virtual ~A() {};
virtual void method3() = 0; // <-- Here
//and a factory function
static A* gimmeAnAyy();
};
class B : public T
{
public:
virtual ~B() {};
virtual void method4() = 0; // <-- and Here
//and a factory function
static B* gimmeABee();
};
If doesn't want to implement the methods 1 and 2 of the T class, give an empty or a default implementation to them, in the T class or in the A and B classes.
But consider this, if you inherits from an interface, is expected that you IMPLEMENT that interface. :)