Diamond Inheritance (C++)

How does virtual inheritance solve the diamond (multiple inheritance) ambiguity?

You want: (Achievable with virtual inheritance)

  A  
/ \
B C
\ /
D

And not: (What happens without virtual inheritance)

A   A  
| |
B C
\ /
D

Virtual inheritance means that there will be only 1 instance of the base A class not 2.

Your type D would have 2 vtable pointers (you can see them in the first diagram), one for B and one for C who virtually inherit A. D's object size is increased because it stores 2 pointers now; however there is only one A now.

So B::A and C::A are the same and so there can be no ambiguous calls from D. If you don't use virtual inheritance you have the second diagram above. And any call to a member of A then becomes ambiguous and you need to specify which path you want to take.

Wikipedia has another good rundown and example here

Diamond inheritance (C++)

Inheritance is the second strongest (more coupling) relations in C++, preceded only by friendship. If you can redesign into using only composition your code will be more loosely coupled. If you cannot, then you should consider whether all your classes should really inherit from the base. Is it due to implementation or just an interface? Will you want to use any element of the hierarchy as a base element? Or are just leaves in your hierarchy that are real Action's? If only leaves are actions and you are adding behavior you can consider Policy based design for this type of composition of behaviors.

The idea is that different (orthogonal) behaviors can be defined in small class sets and then bundled together to provide the real complete behavior. In the example I will consider just one policy that defines whether the action is to be executed now or in the future, and the command to execute.

I provide an abstract class so that different instantiations of the template can be stored (through pointers) in a container or passed to functions as arguments and get called polymorphically.

class ActionDelayPolicy_NoWait;

class ActionBase // Only needed if you want to use polymorphically different actions
{
public:
virtual ~Action() {}
virtual void run() = 0;
};

template < typename Command, typename DelayPolicy = ActionDelayPolicy_NoWait >
class Action : public DelayPolicy, public Command
{
public:
virtual run() {
DelayPolicy::wait(); // inherit wait from DelayPolicy
Command::execute(); // inherit command to execute
}
};

// Real executed code can be written once (for each action to execute)
class CommandSalute
{
public:
void execute() { std::cout << "Hi!" << std::endl; }
};

class CommandSmile
{
public:
void execute() { std::cout << ":)" << std::endl; }
};

// And waiting behaviors can be defined separatedly:
class ActionDelayPolicy_NoWait
{
public:
void wait() const {}
};

// Note that as Action inherits from the policy, the public methods (if required)
// will be publicly available at the place of instantiation
class ActionDelayPolicy_WaitSeconds
{
public:
ActionDelayPolicy_WaitSeconds() : seconds_( 0 ) {}
void wait() const { sleep( seconds_ ); }
void wait_period( int seconds ) { seconds_ = seconds; }
int wait_period() const { return seconds_; }
private:
int seconds_;
};

// Polimorphically execute the action
void execute_action( Action& action )
{
action.run();
}

// Now the usage:
int main()
{
Action< CommandSalute > salute_now;
execute_action( salute_now );

Action< CommandSmile, ActionDelayPolicy_WaitSeconds > smile_later;
smile_later.wait_period( 100 ); // Accessible from the wait policy through inheritance
execute_action( smile_later );
}

The use of inheritance allows public methods from the policy implementations to be accessible through the template instantiation. This disallows the use of aggregation for combining the policies as no new function members could be pushed into the class interface. In the example, the template depends on the policy having a wait() method, which is common to all waiting policies. Now waiting for a time period needs a fixed period time that is set through the period() public method.

In the example, the NoWait policy is just a particular example of the WaitSeconds policy with the period set to 0. This was intentional to mark that the policy interface does not need to be the same. Another waiting policy implementation could be waiting on a number of milliseconds, clock ticks, or until some external event, by providing a class that registers as a callback for the given event.

If you don't need polymorphism you can take out from the example the base class and the virtual methods altogether. While this may seem overly complex for the current example, you can decide on adding other policies to the mix.

While adding new orthogonal behaviors would imply an exponential growth in the number of classes if plain inheritance is used (with polymorphism), with this approach you can just implement each different part separately and glue it together in the Action template.

For example, you could make your action periodic and add an exit policy that determine when to exit the periodic loop. First options that come to mind are LoopPolicy_NRuns and LoopPolicy_TimeSpan, LoopPolicy_Until. This policy method ( exit() in my case ) is called once for each loop. The first implementation counts the number of times it has been called an exits after a fixed number (fixed by the user, as period was fixed in the example above). The second implementation would periodically run the process for a given time period, while the last one will run this process until a given time (clock).

If you are still following me up to here, I would indeed make some changes. The first one is that instead of using a template parameter Command that implements a method execute() I would use functors and probably a templated constructor that takes the command to execute as parameter. The rationale is that this will make it much more extensible in combination with other libraries as boost::bind or boost::lambda, since in that case commands could be bound at the point of instantiation to any free function, functor, or member method of a class.

Now I have to go, but if you are interested I can try posting a modified version.

Diamond inheritance

(i) and (iii) are right. In my experience anyway, most of the time in C++ when I've used multiple inheritance it's been because the bases were interfaces (a concept which doesn't have keyword support in C++, but it is a concept you can execute anyway).

The first sentence of (ii) is right, however your second sentence is talking about virtual functions, which is completely different to virtual inheritance. Virtual inheritance means that there is only one copy of B, and the D and E both have that same copy as their base. There is no difference in terms of functions, but the difference comes in terms of member variables (and base classes) of B.

If there is a function that prints out B's member variable foo; then in case (ii) this function always prints the same value because there is only one foo, but in case (i) calling that function from the D base class may print a different value to calling it from the E base class.

The term "diamond inheritance" wraps all this up in two words that serve as a good mnemonic :)

C++ diamond problem - How to call base method only once

You are asking for something like inheritance on a function level that automatically calls the inherited function and just adds more code. Also you want it to be done in a virtual way just like class inheritance. Pseudo syntax:

class Swimmer : public virtual Creature
{
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
{
std::cout << "I can swim" << std::endl;
}
};

class Flier : public virtual Creature
{
public:
// Virtually inherit from Creature::print and extend it by another line of code
void print() : virtual Creature::print()
{
std::cout << "I can fly" << std::endl;
}
};

class Duck : public Flier, public Swimmer
{
public:
// Inherit from both prints. As they were created using "virtual function inheritance",
// this will "mix" them just like in virtual class inheritance
void print() : Flier::print(), Swimmer::print()
{
std::cout << "I'm a duck" << std::endl;
}
};

So the answer to your question

Is there some built-in way to do this?

is no. Something like this does not exist in C++. Also, I'm not aware of any other language that has something like this. But it is an interesting idea...

Eliminating C++ diamond inheritance by passing a pointer to this to base constructor

Congratulations ! You've just re-invented the principle of composition over inheritance !

If this works with your design, it means that C was in fact not a kind of A, and there was no real justification to use inheritance in first place.

But don't forget the rule of 5 ! While your approach should work in principle, you have a nasty bug here : with your current code, if you copy a D object, its clone uses the wrong reference to the base (it doesn't refer to it's own base, which can lead to very nasty bugs...

Demo of the hidden problem

Let's make A::get_num() a little bit more wordy, so that it tells us about the address of the object that invokes it:

int get_num() const { 
cout << "get_num for " << (void*)this <<endl;
return num;
}

Let's add a member function to C, for the purpose of the demo:

void show_oops() { fooc(); }

And same for D:

void show() { food(); }

Now we can experiment the problem by running this small snippet:

int main() {
D d;
cout<<"d is "<<(void*)&d<<endl;
d.show();
d.show_oops();
D d2=d;
cout<<"d2 is "<<(void*)&d2<<endl;
d2.show();
d2.show_oops();
}

Here an online demo. You will notice that d2 does produce inconsistent results, like here:

d is  0x7fffe0fd11a0
get_num for 0x7fffe0fd11a0
get_num for 0x7fffe0fd11a0
d2 is 0x7fffe0fd11b0
get_num for 0x7fffe0fd11b0
get_num for 0x7fffe0fd11a0 <<< OUCH !! refers to the A element in d !!

Not only do you refer to the wrong object, but if the d object would decease, you would have a dangling reference, so UB.



Related Topics



Leave a reply



Submit