The process of creating a class that includes virtual inheritance

In many textbooks describing the use of virtual base classes (usually used to solve the problem with diamonds), they often have code similar to the design of this structure:

class Animal { public: Animal() { cout << "Creating Animal\n"; } }; /////////////////////////// class FourLegs : virtual public Animal { public: FourLegs() { cout << "Creating FourLegs\n"; } }; /////////////////////////// class Mammal : virtual public Animal { public: Mammal() { cout << "Creating Mammal\n"; } }; /////////////////////////// class Fox : public FourLegs, public Mammal { public: Fox() { cout << "Creating Fox\n"; } }; 

When I create an instance of Fox, I get the expected result, only one created by Animal:

 Creating Animal Creating FourLegs Creating Mammal Creating Fox 

As you can see, I have two level 2 classes, inherited practically. Now, if only the class one tier-2 is inherited practically, and the other is inherited simply publicly, interesting results can arise. For example, if FourLegs is inherited public and Mammal is inherited by the virtual public, this is the result:

 Creating Animal Creating Animal Creating FourLegs Creating Mammal Creating Fox 

This is strange and begs the question: What is the complete process of creating a class that includes virtual inheritance somewhere in the inheritance tree?

On the other hand, if I FourLegs, if I inherited virtual publishing, and Mammal is inherited publicly, then the output will be just as normal (as if nothing had been inherited by virtual public):

 Creating Animal Creating FourLegs Creating Animal Creating Mammal Creating Fox 
+6
source share
2 answers

Straight from the standard, 12.6.2 / 10 [class.base.init]:

In the constructor without delegation, initialization is performed in the following order:

  • First, and only for the constructor of the derived class (1.8) itself, the virtual base classes are initialized in the order in which they appear at the first intersection from left to right left to right of the directed acyclic base graph classes, where "from left to right" is the order in which the base classes in the base specification list of a derived class.

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

  • The non-static data elements are then initialized in the order in which they were declared in the class definition (again, regardless of the order of the mem initializers).

  • Finally, the compound instruction of the constructor body is executed.

[Note. The declaration order is set to ensure that the base and element subobjects are destroyed in the reverse order of initialization. -end note]

The first pool explains how initialization is done using classes that include virtual inheritance.

+3
source

An unexpected conclusion is not unexpected. This is because FourLegs derived from Animal and must call the Animal constructor. To prevent a problem, an established virtual agreement is required to extract all intermediate classes. The main problem with your example is that the FourLegs concept FourLegs used as an inherited trait, while it should be used as a composition trait. That is, there is a field describing the number of legs that a mammal / animal is inside Mammal or Animal (depending on specific requirements), and derived classes inherit the field.

0
source

Source: https://habr.com/ru/post/918897/


All Articles