在 OS X 上使用 Xcode 5.1 编译以下代码时遇到意外错误。 Apple LLVM 版本 5.1 (clang-503.0.40)(基于 LLVM 3.4svn)
class GrandParent
{
public:
GrandParent(int age) : m_age(age)
{
}
virtual ~GrandParent() {}
private:
GrandParent();
GrandParent(const GrandParent&);
const GrandParent& operator=(const GrandParent&);
int m_age;
};
class Parent1 : public virtual GrandParent
{
public:
Parent1(int age) : m_age(age)
{
}
virtual ~Parent1() {}
private:
Parent1();
Parent1(const Parent1&);
const Parent1& operator=(const Parent1&);
int m_age;
};
class Parent2 : public virtual GrandParent
{
public:
Parent2(int age) : m_age(age)
{
}
virtual ~Parent2() {}
private:
Parent2();
Parent2(const Parent2&);
const Parent2& operator=(const Parent2&);
int m_age;
};
class Child : public Parent1, public Parent2
{
public:
Child(int grandParentAge, int parent1Age, int parent2Age, int childAge) :
GrandParent(grandParentAge),
Parent1(parent1Age),
Parent2(parent2Age),
m_age(childAge)
{
}
virtual ~Child() {}
private:
Child();
Child(const Child&);
const Child& operator=(const Child&);
int m_age;
};
报告的错误是:
error: inherited virtual base class 'GrandParent' has private default constructor
Parent1(int age) : m_age(age)
^
note: declared private here
GrandParent();
^
error: inherited virtual base class 'GrandParent' has private default constructor
Parent2(int age) : m_age(age)
^
note: declared private here
GrandParent();
我的理解是,虚拟基类(GrandParent)的构造函数不会被继承它的类(Parent1或Parent2)调用。相反,构造函数由具体类(Child)的构造函数调用。
这是正确的吗?
如果我为 GrandParent 提供默认构造函数,它可以编译正常。但是,如果我构造一个子对象:
Child child(80, 50, 49, 20);
检查一下我可以看到:
Child) child = {
Parent1 = {
GrandParent = (m_age = 49)
m_age = 50
}
Parent2 = {
GrandParent = (m_age = 80)
m_age = 49
}
m_age = 20
因此,使用 Parent1 时祖 parent 的年龄不正确,但使用 Parent2 时祖 parent 的年龄是正确的。
我是不是误会了什么?或者该错误可能是编译器错误?
更新
如果我更新 Parent1 的 ctor(并对 Parent2 执行相同操作):
Parent1(int 年龄) : GrandParent(100), m_age(年龄) { }
现在可以编译了。检查这些值可以发现:
(Child) child = {
Parent1 = {
GrandParent = (m_age = 49)
m_age = 50
}
Parent2 = {
GrandParent = (m_age = 80)
m_age = 49
}
m_age = 20
这显然是不对的。此外,修改后的代码使用VS 2013 Express在Windows上编译,检查值正确。
最佳答案
所有定义的角色,无论是否默认,都必须有效。
虽然除了最派生的构造函数之外,在运行时都会跳过虚拟基的初始化,但它仍然必须有效。
引自 C++14 最终草案 (n3936):
12.6.2 Initializing bases and members
[class.base.init]
7 The expression-list or braced-init-list in a mem-initializer is used to initialize the designated subobject (or, in the case of a delegating constructor, the complete class object) according to the initialization rules of 8.5 for direct-initialization.
[ example omitted ]
The initialization performed by each mem-initializer constitutes a full-expression. Any expression in a mem-initializer is evaluated as part of the full-expression that performs the initialization. A mem-initializer where the mem-initializer-id denotes a virtual base class is ignored during execution of a constructor of any class that is not the most derived class.
8 In a non-delegating constructor, if a given potentially constructed subobject is not designated by a meminitializer-id (including the case where there is no mem-initializer-list because the constructor has no ctor-initializer), then
- if the entity is a non-static data member that has a brace-or-equal-initializer and either
- the constructor’s class is a union (9.5), and no other variant member of that union is designated by a mem-initializer-id or
- the constructor’s class is not a union, and, if the entity is a member of an anonymous union, no other member of that union is designated by a mem-initializer-id, the entity is initialized as specified in 8.5;
- otherwise, if the entity is an anonymous union or a variant member (9.5), no initialization is performed;
- otherwise, the entity is default-initialized (8.5).
[ 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 ]
我特别建议您注意最后一条注释,您可能会用它作为理由。
问题是,注释是非规范性的,并且该注释与其前面的规范性文本完全矛盾。
似乎 clang++-3.5.0 将此注释视为福音,而 g++-4.9.0 则没有:
http://coliru.stacked-crooked.com/a/ded8d46cc29ac79f
关于c++ - 使用虚拟继承时初始化基类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26098900/