考虑代码:
#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
}
我已编写代码以了解 12.6.2 / 8 N37973 中的规则说明:
[注意:抽象类(10.4)永远不是最派生的类,因此 它的构造函数永远不会初始化虚拟基类,因此 可以省略相应的mem初始化器。 - 结束说明]
如果我们在B()
中省略mem-initializer并将基类A
设为非虚拟,我们将得到相同的结果。
那么我引用的那个注释的目的是什么?
答案 0 :(得分:3)
它在谈论这样的事情:
#include <iostream>
using std::cout;
using std::endl;
struct A
{
virtual void foo(){ };
// N.B.: no default ctor
A(int)
{
cout << "A(int)" << endl;
}
};
struct B : virtual A
{
virtual void bar() = 0;
B()
{
cout << "B()" << endl;
}
};
struct C : B
{
void bar(){ };
C() : A(10), B()
{
cout << "C()" << endl;
}
};
C c;
int main()
{
}
如果A
不是B
的虚拟基础,或B
不是抽象的,那么B::B()
必须有一个合适的 mem-initializer < / em> for A
;但是,由于B
是抽象的,A
是虚拟基础,而B
的构造函数永远不会构造A
,因此 mem-initializer 可以省略。请注意,g ++目前没有实现此规则,仍然需要B
的 mem-initializer (它永远不会实际使用)。然而,Clang确实如此。 Demo
另请参阅引入此规则的CWG issue 257,后面的CWG issue 1658进一步修改了措辞。相关GCC错误报告为bug 19249和53878。
答案 1 :(得分:2)
如果B
从A
继承非虚拟,那么B
的构造函数必须初始化A
基类子对象。由于A
有默认构造函数,因此您不必在 ctor-initializer 中明确提及A
B
。但是,如果A
没有默认构造函数,B
从A
继承非虚拟,则必须在 ctor-中显式初始化A
B
的初始化程序。
如果B
实际上从A
继承,而B
是一个抽象类,那么即使A
没有默认构造函数,您仍然不需要在{em> ctor-initializer 中提及A
的{{1}}。这是因为B
的构造函数永远不会负责初始化B
子对象;相反,派生程度最高的类的构造函数是必须初始化A
子对象的构造函数,因为A
是一个虚拟基类。
答案 2 :(得分:1)
您的示例没有太多证明,因为虚拟基础A
具有默认构造函数。您永远不必为虚拟基类(或任何基类)显式调用默认构造函数。编译器将在需要的任何地方隐式调用该默认构造函数,无论您是否自己明确地完成了它。
删除默认构造函数,并在A
struct A
{
A(int)
{
cout << "A()" << endl;
}
};
有问题的说明告诉您,现在您必须从A
(直接来自A
的每个非抽象类中显式调用基础A
的构造函数或间接)。在您的情况下,您必须从C
struct C : B
{
void bar(){ }
C() : A(42)
{
cout << "C()" << endl;
}
};
A
因为C不是抽象类。
但是您不必从B
的构造函数初始化B
,因为struct B : virtual A
{
virtual void bar() = 0;
B()
{
cout << "B()" << endl;
}
};
是一个抽象类。即此
A
应该在C ++ 11中编译,即使是“经典”(pre-C ++ 11)语言规则也需要从B
的构造函数中明确初始化B
。< / p>
请注意,即使在C ++ 11模式下,ideone使用的GCC编译器(例如)仍会报告类{{1}}的上述定义的错误。显然,它还没有更新到遵循C ++ 11的规则。