Virtual inheritance versus non-standard constructors

This code is rejected (at least) by MSVC, ICC and GCC:

class A { public: A( int ) { } }; class B: virtual public A { public: //B(): A( -1 ) { } // uncomment to make it compilable virtual void do_something() = 0; }; class C: public B { public: C(): A( 1 ) { } virtual void do_something() { } }; int main() { C c; return 0; } 

based

 error : no default constructor exists for class "A" class B: virtual public A { ^ detected during implicit generation of "B::B()" at line 14 

Questions:

  • If the code is really invalid, how exactly does this follow from the standard? AFAICT, 10.4 / 2 and 1.8 / 4 taken together mean that B cannot be the type of the derived class itself and, therefore, from 12.6.2 / 10 we have that B can never name the constructors of A. (Section numbers for C + + 11.)

  • If the code is valid, compilers that violate the standard, requiring constructors that they could not name? Note that not only do they want to call A :: A () from B :: B (), but they want to do this when compiling C :: C () (double weird).

PS This was originally asked on the ICC forum, but published here due to the fact that it is not limited to this compiler (and details are not reported).

+7
source share
3 answers

Clang shows the error as:

 error: call to implicitly-deleted default constructor of 'B' C(): A( 1 ) { } ^ 

12.1 / 5 says: "By default, the default constructor for class X is defined as remote if [...] any [...] virtual base class [...] has class types M [...] and [. ..] M does not have a default constructor [...]. "

+4
source

I think you are trying to get a "theorem" from the facts that can be found in the standard, and then you expect the standard to recognize the existence of this "theorem". The standard does not. He does not seek to find and include all possible โ€œtheoremsโ€ that can be obtained from the standard text.

Your โ€œtheoremโ€ is perfectly true (unless I miss something). You are right, since class B is abstract, this class can never be used as the most derived class. This immediately means that class B will never get the opportunity to build its virtual base A And this means that technically in B compiler does not have to worry about the availability and / or availability of the corresponding constructors in A or in any other virtual databases.

But the standard simply does not make this connection and does not want to make it. He does not consider constructors of abstract classes in any special way. The requirements for such constructors are the same as for non-abstract classes.

You can call try, suggesting it as a possible improvement to the standard committee.

+3
source

It seems like 12.6.2 / 4 forbids this to me:

If the given non-static data member or base class is not named mem-initializer-id (including the case where there is no mem-initializer-list, because the constructor does not have a ctor initializer), then

- If the object is a non-statistical data element (possibly cv-qualified), the class type (or its array) or the base class, as well as the entity class - non-POD class, the object is initialized by default (8.5) ...

It seems to me that regardless of the class that is the virtual base, the default constructor B is still synthesized by the compiler, and such a default constructor does not know how to build its base A ("the object is initialized by default (8.5)").

0
source

All Articles