Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mixing virtual and non-virtual inheritance of a base class

This is the code:

struct Biology
{    
    Biology() { cout << "Biology CTOR" << endl; }
};

struct Human : Biology
{    
    Human() { cout << "Human CTOR" << endl; }
};

struct Animal : virtual Biology
{
    Animal() { cout << "Animal CTOR" << endl; }
};

struct Centaur : Human, Animal
{
    Centaur() { cout << "Centaur CTOR" << endl; }
};

int main()
{   
   Centaur c;

   return 0;
}

This code prints:

Biology CTOR
Biology CTOR
Human CTOR
Animal CTOR
Centaur CTOR

Why?

Since we create a Centaur object, we start from building the Centaur by constructing Human, Animal and finally Centaur (we start from the less derived to the most derived).

Let's start from Human: Human inherits from Biology, so we call Biology's constructor first. Now that Human's base class is constructed, we can finally construct the Human itself. But instead, Biology gets constructed again!

Why? What's happening behind the scenes?

Please note that it was completely intentional leaving Animal inheriting virtually from Biology and, at the same time, it was also intentional leaving Human non-virtually inheriting from Biology.

We are solving the Dreaded Diamond in an incorrect way: both Human and Animal should virtually inherit Biology to make this work.

I'm just curious.

Also, see this code:

struct Biology
{    
    Biology() { cout << "Biology CTOR" << endl; }
};

struct Human : virtual Biology
{
    Human() { cout << "Human CTOR" << endl; }
};

struct Animal : Biology
{    
    Animal() { cout << "Animal CTOR" << endl; }
};

struct Centaur : Human, Animal
{
    Centaur() { cout << "Centaur CTOR" << endl; }
};

int main()
{   
   Centaur c;

   return 0;
}

Here we have Human inheriting virtually from Biology, while Animal is set to inherit in the "classic way".

But this time, the output is different:

Biology CTOR
Human CTOR
Biology CTOR
Animal CTOR
Centaur CTOR

This because Centaur inherits at first from Human and then from Animal.

Had the order been the inverse, we'd have achieved the same result as before, in the first example - two Biology instances being constructed in a row.

What's the logic of this?

Please try to explain your way, I've already checked tons of websites speaking about this. But none seems to satisfy my request.

like image 494
gedamial Avatar asked Feb 10 '16 11:02

gedamial


People also ask

Why is there a need for virtual base class in hybrid inheritance?

Virtual base classes are used in virtual inheritance in a way of preventing multiple “instances” of a given class appearing in an inheritance hierarchy when using multiple inheritances.

Can multiple inheritance have virtual classes?

Instead, if classes B and C inherit virtually from class A , then objects of class D will contain only one set of the member variables from class A . This feature is most useful for multiple inheritance, as it makes the virtual base a common subobject for the deriving class and all classes that are derived from it.

Should we use multiple inheritance in C++?

Multiple inheritance in languages with C++/Java style constructors exacerbates the inheritance problem of constructors and constructor chaining, thereby creating maintenance and extensibility problems in these languages.

What is the effect of using virtual inheritance in C++ in the context of multiple inheritance?

When we use virtual inheritance, we are guaranteed to get only a single instance of the common base class. In other words, the radio class will have only a single instance of the storable class, shared by both the transmitter and receiver classes.

What is a virtual base class in inheritance?

Virtual base classes are used in virtual inheritance in a way of preventing multiple “instances” of a given class appearing in an inheritance hierarchy when using multiple inheritances. Consider the situation where we have one class A .This class is A is inherited by two other classes B and C.

What is non virtual inheritance in C++?

Non virtual inheritance is an exclusive relationship, like membership. A class can be the non-virtual base class of one other class in a given complete object. This implies that a class can override virtual functions of a non virtual base class without causing conflicts or issues.

What is a non-virtual base class?

A class can be the non-virtual base class of one other class in a given complete object. This implies that a class can override virtual functions of a non virtual base class without causing conflicts or issues. A constructor can also initialize non virtual bases reliably.

What is a virtual base class in Java?

Virtual base classes offer a way to save space and avoid ambiguities in class hierarchies that use multiple inheritances. When a base class is specified as a virtual base, it can act as an indirect base more than once without duplication of its data members.


3 Answers

It's clear from the output that two Biology objects are instantiated. That is because you've made only one inheritance virtual. Two base class instances is the cause of ambiguity in dreaded diamond problem and the solution is to make (as we know) both inheritances of Biology virtual.

Recap of the hierarchy:

Biology  Biology    |       |     # one and only one inheritance virtual  Human   Animal     \     /     Centaur 

Ok, let's read the output again with these rules in mind:

  • Base classes are constructed before derived classes.
  • Base classes are constructed in order in which they appear in the base-specifier-list.
  • Virtual base classes are constructed before non-virtual ones by the most derived class - see this.

1st output - Animal virtually inherits from Biology:

Biology CTOR     # virtual base class inherited from Animal Biology CTOR     # non-virtual base class of Human Human CTOR       # Human itself Animal CTOR      # Animal's virtual base class already constructed Centaur CTOR 

2nd output - Human virtually inherits from Biology:

Biology CTOR     # virtual base class inherited from Human Human CTOR       # Human's virtual base class already constructed Biology CTOR     # non-virtual base class of Animal Animal CTOR      # Animal itself Centaur CTOR 

More informative standard paragraph ([class.base.init]/10):

In a non-delegating constructor, initialization proceeds in the following order:

— First, and only for the constructor of the most derived class (1.8), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where “left-to-right” is the order of appearance of the base classes in the derived class base-specifier-list.

— Then, direct base classes are initialized in declaration order as they appear in the base-specifier-list (regardless of the order of the mem-initializers).

...

like image 91
LogicStuff Avatar answered Sep 23 '22 10:09

LogicStuff


Non virtual inheritance is an exclusive relationship, like membership. A class can be the non-virtual base class of one other class in a given complete object.

This implies that a class can override virtual functions of a non virtual base class without causing conflicts or issues.

A constructor can also initialize non virtual bases reliably.

Only virtual bases can be direct base classes of many indirect bases of a complete object. Because a virtual base class can be shared, overriders can conflict.

A constructor can try to initialize a virtual base subobject in the ctor-init-list, but if the class is further derived, that part of the ctor-init-list will be ignored.

like image 20
curiousguy Avatar answered Sep 20 '22 10:09

curiousguy


  1. All the base classes that inherit virtually from Biology share one instance of Biology base between them.
  2. All the base classes that inherit non-virtually from Biology have one instance each of Biology.

You have one base in each category, therefore you have one instance of Biology brought in by Human (and in principle shared with others) and one instance brought in by Animal (never shared with any other base class).

like image 33
Toby Speight Avatar answered Sep 20 '22 10:09

Toby Speight