Consider the code:
#include <iostream>
using std::cout;
using std::endl;
struct A
{
virtual void foo(){ };
A()
{
cout << "A()" << endl;
}
};
struct B : virtual A
{
virtual void bar() = 0;
B() : A() //mem-initializer of virtual base class
{
cout << "B()" << endl;
}
};
struct C : B
{
void bar(){ };
C() : B()
{
cout << "C()" << endl;
}
};
C c;
int main()
{
//A()
//B()
//C()
//Is output
}
I've written the code to understand the rule's note from 12.6.2/8 N37973:
[Note: An abstract class (10.4) is never a most derived class, thus its constructors never initialize virtual base classes, therefore the corresponding mem-initializers may be omitted. — end note]
If we omit mem-initializer in the B()
and make the base class A
as non-virtual we'll have the same result.
So what purpose of the note that I cited?
If
B
inherits non-virtually fromA
, thenB
's constructor must initialize theA
base class subobject. SinceA
has a default constructor, you don't have to explicitly mentionA
in the ctor-initializer forB
. However, ifA
did not have a default constructor, andB
inherited non-virtually fromA
, you would have to explicitly initializeA
in the ctor-initializer forB
.If
B
inherits virtually fromA
, andB
is an abstract class, then even ifA
has no default constructor, you still don't need to mentionA
in the ctor-initializer forB
. This is becauseB
's constructor will never have the responsibility of initializing theA
subobject; instead, the most derived class's constructor is the one that has to initialize theA
subobject, sinceA
is a virtual base class.It's talking about something like this:
If
A
weren't a virtual base ofB
, orB
weren't abstract, thenB::B()
must have an appropriate mem-initializer forA
; however, sinceB
is abstract andA
is a virtual base, andB
's constructor will never actually constructA
, the mem-initializer can be omitted. Note that g++ currently does not implement this rule and still requires a mem-initializer forB
(which it will never actually use). Clang does, however. Demo.See also CWG issue 257, which introduced this rule, with the phrasing further altered later by CWG issue 1658. The relevant GCC bug reports are bug 19249 and 53878.
Your example doesn't demonstrate much, since the virtual base
A
has a default constructor. You never have to explicitly invoke default constructor for a virtual base class (or any base class for that matter). The compiler will invoke that default constructor implicitly everywhere it is needed, regardless of whether you've done it explicitly yourself.Remove the default constructor and provide a constructor with a parameter in
A
The note in question is telling you that now you will have to explicitly invoke the constructor for base
A
from each non-abstract class virtually derived fromA
(directly or indirectly). In your case you have to explicitly initializeA
from the constructor ofC
since C is not an abstract class.
But you don't have to initialize
A
from the constructor ofB
, sinceB
is an abstract class. I.e. thisshould compile in C++11, even tough the "classic" (pre-C++11) language rules required an explicit initialization of
A
from the constructor ofB
as well.Note that GCC compiler used by ideone (for one example), still reports an error for the above definition of class
B
even in C++11 mode. Apparently, it has not been updated yet to follow that rule of C++11.