多级继承构造函数的执行
multi level inheritance constructor execution
class A {
public:
A(int) {
cout << "Base class" << endl;
}
};
class B : virtual public A {
public:
virtual void do_something() = 0;
};
class C : public B {
public:
C()
: A(1) {
cout << "C class" << endl;
}
virtual void do_something() {
}
};
编译错误:当为C创建对象时,编译器产生类似
的错误错误:没有匹配的函数调用' A::A() '
为什么编译器期望类A的默认构造函数?
由于C::C()
中C
的B
部分没有显式初始化,编译器使用B
的默认构造函数进行初始化。
C()
: A(1) {
cout << "C class" << endl;
}
等价于:
C()
: B(), A(1) {
cout << "C class" << endl;
}
B
的默认构造函数尝试使用不存在的A
的默认构造函数来初始化A
部分。这是编译器的错误信息
您可以通过以下方法之一修复它:
- 提供
A
的默认构造函数 - 提供
B
的默认构造函数,其中使用A(int)
初始化B
的A
部分。
为什么编译器想要B::B()
中的A::A()
?因为它不知道,在运行时,C
的一个实例将被构造。
考虑以下场景:
#include <iostream>
using namespace std;
class A
{
public:
A(int)
{
cout << "Came to A(int)" << endl;
}
};
class B : virtual public A
{
public:
virtual void do_something(){};
};
int main()
{
B b;
}
很明显为什么B::B()
需要调用A::A(int)
或期望A::A()
。由于编译器不能先验地判断B
是否是最派生的类,因此它必须确保有一种方法可以在必要时从B
初始化A
。
B
没有默认构造函数。
B
没有用户定义的默认构造函数,编译器提供的默认构造函数是错误的,因为它必须使用A
的默认构造函数,而A
没有。
当B
被用作基类时,即使B
的默认构造函数不应该调用A
的构造函数,如果你想使用B
,你仍然需要一个有效的默认构造函数
下面是c++ 11中问题的详细说明:
-
由于
B
没有用户声明的构造函数,因此没有参数的构造函数被隐式声明为默认值。然而,由于A
没有默认构造函数,这个构造函数被定义为删除的。Ref[class.ctor]#5
。(这实际上意味着B
永远不能被创建,因为它没有未删除的构造函数)。 -
C
的构造函数在初始化列表中没有提到B
,因此B
子对象是默认初始化的。Ref[class.base.init]#8
-
没有可访问的默认构造函数的对象的默认初始化意味着程序是病态的。Ref
[dcl.init]#6
在[class.base.init]#8
中有一个子句,如果基类是抽象类的虚基类,则不需要构造函数。然而,这里的情况并非如此。A
是这样一个类,但B
不是。
Summary - C
的B
子对象没有有效的构造函数
- 无法在构造函数中执行设置元素插入
- 运算符 new 的执行顺序和构造函数的参数
- 在构造函数中删除后继续执行
- 在执行new期间是否可以在构造函数中传递不同的参数?
- 如果普通默认构造函数不执行任何操作,为什么我们不能使用 malloc 创建平凡可构造的对象?
- 如何执行参数化构造函数的调用?
- 显式构造函数仍在执行转换
- 遵循 C++ 中的构造函数执行顺序
- 模板化构造函数无法执行转换
- 如果默认构造函数不执行任何操作,则目的是什么
- 复制构造函数如何执行?
- 使用构造函数的可变参数中的其他模板化类执行模板化类的初始化
- 如何为基类构造函数中的每个子类执行特定任务
- Arduino 上的 Sketch 停止在对象构造函数中执行
- 具有模板参数推导的构造函数意外执行
- 将执行哪个构造函数
- C++:程序的执行(构造函数、析构函数、赋值运算符等)
- C++类组合 - 何时执行构造函数和析构函数
- 在C++中执行构造函数
- C++ 此指针不执行构造函数