Virtual inheritance and base class base class

Consider the following code:

class A {
};

class B : public A {
};

class C : public B{ 
    public:
    C() : A() {}  // ERROR, A is not a direct base of B
};

      

In this case, GCC (4.8.1, C ++ 99) gives me the correct error (I understand this behavior):

prog.cpp: 12: 8: error: type 'a is not a direct base' c

However, if inheritance between b and a is virtual, this does not happen:

class A {
};

class B : virtual public A {
};

class C : public B{
    public:
    C() : A() {}  // OK with virtual inheritance
};

      

Why does it work? Is A now a direct base for the C compiler?

+3


source to share


3 answers


Why does it work?

According to the standard (10.1.4 in FIDS), "for each individual base class specified as virtual, the most derived object must contain one base class subobject of that type."



The virtual base is shared among all classes derived from it for an object instance. Since a constructor can only be called once for a given instaniation object, you must explicitly call the constructor in the derived class itself, because the compiler does not know how many classes are using the virtual base. This is because the compiler will start from the base class of the constructor and work with the most derived class. Classes that inherit directly from the virtual base class will not, by the standard, call the constructor of the virtual base classes, so it must be called explicitly.

0


source


In general, as C ++ tries to solve the diamond inheritance problem http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem (whether good or bad solution is left as an exercise for the reader).

All inheritance is a combination of is-a and aa relationships ... you must instantiate the parent. If you have the following classes:

class a;
class b : a;
class c : a;
class d : b,c;

      

Then you created an instance of a for each b and c. d won't know which one to use.



C ++ solves this by allowing virtual inheritance, which is highly reliable inheritance that allows b and c to share the same a if inherited in d (this is much more complicated than that, but you can read about it yourself).

The most derived type in the chain must be able to override the instantiation of the shared class to manage differences in how the shared class is inherited by parent classes. Let's take the following example:

class a {int x; public: a(int xx) {x=xx;} int get_x() {return x;}};
class b : public virtual a { public: b(): a(10){}};
class c : public virtual a { public: c(): a(15){}};
class d : public virtual b, public virtual c {public: d() : a (20) {}};
int main() {
    d dd;
    std::cout << dd.get_x() << std::endl;//20, d constructor "wins"
    return 0;
}

      

If d has not defined how the instance was created a

, it will have definitions for conflicting instances (from b

and c

). C ++ handles this by forcing the most derived class in the inheritance chain to create all parent classes (the above would be barf if it did d

NOT explicitly instantiate it a

, though if it a

provided a default constructor that could be implicitly used) and ignoring all parent instances.

+2


source


From N3337, 12.6.2

Initialization of bases and members

In the definition of a constructor for a class, initializers for direct and virtual base subobjects and non-static data members can be specified with a ctor initializer, which has the form

Perhaps whoever has a better version of the standard can check it out.

0


source







All Articles