I have an abstract base class which acts as an interface.
I have two "sets" of derived classes, which implement half of the abstract class. ( one "set" defines the abstract virtual methods related to initialization, the other "set" defines those related to the actual "work". )
I then have derived classes which use multiple inheritance to construct fully defined classes ( and does not add anything itself ).
So: ( bad pseudocode )
class AbsBase { virtual void init() = 0; virtual void work() = 0; } class AbsInit : public AbsBase { void init() { do_this(); } // work() still abs } class AbsWork : public AbsBase { void work() { do_this(); } // init() still abs } class NotAbsTotal : public AbsInit, public AbsWork { // Nothing, both should be defined }
First of all, can I do this? Can I inherit from two classes which are both derived from the same Base? (I hope so).
Here is the "real problem", though (I lied a bit above to simplify the example).
What I have really gone and done is add non abstract accessors methods to the base class:
class AbsBase { public: void init() { init_impl(); } void work() { work_impl(); } private: virtual void init_impl() = 0; virtual void work_impl() = 0; }
Because, a common idiom is to make all virtual methods private.
Unfortunately, now both AbsInit, and AbsWork inherit these methods, and so NotAbsTotal inherits "two of each" ( I realize I may be butchering what is really happening at compile time ).
Anyway, g++ complains that: "request for member init() is ambiguous" when trying to use the class.
I assume that, had I used my AbsBase class as a pure interface, this would have been avoided ( assuming that the top example is valid ).
So: - Am I way off with my implementation? - Is this a limitation of the idiom of making virtual methods private? - How do I refactor my code to do what I want? ( Provide one common interface, but allow a way to swap out implementations for "sets" of member functions )
Edit:
Seems I am not the first one: http://en.wikipedia.org/wiki/Diamond_problem
Seems Virtual Inheritance is the solution here. I have heard of virtual inheritance before, but I have not wrapped my head around it. I am still open to suggestions.
You can derive a class from any number of base classes. Deriving a class from more than one direct base class is called multiple inheritance. The order of derivation is relevant only to determine the order of default initialization by constructors and cleanup by destructors.
Multiple Inheritance is a feature of C++ where a class can inherit from more than one classes. The constructors of inherited classes are called in the same order in which they are inherited. For example, in the following program, B's constructor is called before A's constructor.
C++ Multiple Inheritance In C++ programming, a class can be derived from more than one parent. For example, A class Bat is derived from base classes Mammal and WingedAnimal .
Explanation: The derived class must not be abstract. This is because the abstract classes doesn't have constructor and hence we won't be having the capability to have instances. This will restrict the use of multiple inheritance.
It looks like you want to do virtual inheritance. Whether that turns out to actually be a good idea is another question, but here's how you do it:
class AbsBase {...}; class AbsInit: public virtual AbsBase {...}; class AbsWork: public virtual AbsBase {...}; class NotAbsTotal: public AbsInit, public AbsWork {...};
Basically, the default, non-virtual multiple inheritance will include a copy of each base class in the derived class, and includes all their methods. This is why you have two copies of AbsBase -- and the reason your method use is ambiguous is both sets of methods are loaded, so C++ has no way to know which copy to access!
Virtual inheritance condenses all references to a virtual base class into one datastructure. This should make the methods from the base class unambiguous again. However, note: if there is additional data in the two intermediate classes, there may be some small additional runtime overhead, to enable the code to find the shared virtual base class.
You need to to declare the inheritance as virtual:
struct AbsBase { virtual void init() = 0; virtual void work() = 0; }; struct AbsInit : virtual public AbsBase { void init() { } }; struct AbsWork : virtual public AbsBase { void work() { } }; struct NotAbsTotal : virtual public AbsInit, virtual public AbsWork { }; void f(NotAbsTotal *p) { p->init(); } NotAbsTotal x;
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With