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.
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:
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.