C++ 类派生自C++;:派生类正在尝试调用根基类构造函数
我很抱歉,如果这感觉像是一个廉价的续集 我有一个菱形继承,其中C++ 类派生自C++;:派生类正在尝试调用根基类构造函数,c++,multiple-inheritance,instantiation,C++,Multiple Inheritance,Instantiation,我很抱歉,如果这感觉像是一个廉价的续集 我有一个菱形继承,其中D是从B和C派生出来的,而这两者又是从a派生出来的(实际上)A、B和C都是抽象的,多亏了对我前面问题的回答,编译器现在知道了,一切都很好 现在,我需要创建一个派生自D的类E。据我所知,通常构造函数E::E应该调用D::D,而D::D的工作就是调用所有A::A、B::B和C::C 但是我的编译器确实坚持让E::E调用A::A本身 我举了一个简单的例子: class A { //abstract
D
是从B
和C
派生出来的,而这两者又是从a
派生出来的(实际上)<代码>A、B
和C
都是抽象的,多亏了对我前面问题的回答,编译器现在知道了,一切都很好
现在,我需要创建一个派生自D
的类E
。据我所知,通常构造函数E::E
应该调用D::D
,而D::D
的工作就是调用所有A::A
、B::B
和C::C
但是我的编译器确实坚持让E::E
调用A::A
本身
我举了一个简单的例子:
class A { //abstract
protected:
A(int foo) {}
virtual void f() =0;
};
class B: public virtual A { // abstract
protected:
B() {}
};
class C: public virtual A { // abstract
protected:
C() {}
};
class D: public B, public C { // concrete
public:
D(int foo, int bar) :A(foo) {}
void f() {}
};
class E: public D { // concrete
public:
E(int foo, int bar, int buz) :D(foo, bar) {}
};
int main()
{
return 0;
}
下面是编译错误:
$ g++ test.cpp
test.cpp: In constructor ‘E::E(int, int, int)’:
test.cpp:25:49: error: no matching function for call to ‘A::A()’
25 | E(int foo, int bar, int buz) :D(foo, bar) {}
| ^
test.cpp:3:9: note: candidate: ‘A::A(int)’
3 | A(int foo) {}
| ^
test.cpp:3:9: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(const A&)’
1 | class A { //abstract
| ^
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
test.cpp:1:7: note: candidate: ‘constexpr A::A(A&&)’
test.cpp:1:7: note: candidate expects 1 argument, 0 provided
我知道虚拟继承是正确的,我知道编译器知道哪些类是抽象的,哪些是可实例化的,因为如果我删除类E
,代码就会编译
我错过了什么
但我的编译器确实坚持让E::E调用A::A本身
正如我在回答之前的问题时所解释的:“最派生类的构造函数调用虚拟基的构造函数”
包含虚拟基的层次结构中的所有非抽象类都必须正确初始化虚拟基,因为它们可能被实例化为最派生的类。例如,如果创建E
的实例,则初始化虚拟基A
的是E
的构造函数
在您的代码中,E
的构造函数试图通过省略初始化器来使用A
的默认构造函数。但是A
不是默认可构造的,因此程序的格式不正确
我错过了什么
在E
的构造函数中,虚拟基A
的初始化器
据我所知,没有办法将虚拟基的构造委托给另一个具体的基,例如
D
,编译器会告诉您什么是可用的构造函数。您可以看到您定义的一个(int),以及复制和移动构造函数。通过定义自己的构造函数,可以告诉编译器不要声明默认构造函数。请参见另一个问题中的示例,例如当B
被视为可实例化时,它必须能够初始化A
。在当前的示例中,我想不出有什么场景需要E
直接初始化a
。此外,如果我将E
的构造函数定义为E::E(…):D(foo,bar),A(foo){}
,那么D::D(…):A(foo)
会发生什么?是否会有两个A
实例?@scozy我想不出一个场景需要E直接初始化A
,不清楚你为什么这么想。E有一个虚拟的基a(基是否直接无关),它是具体的,因此E必须直接初始化a的场景是E被实例化为最派生的对象的场景。@scozyD::D(…):a(foo)会发生什么?
就像我在另一个答案中写的那样:“您只需知道,如果具体类不是您正在编写的类,则不一定会发生特定的初始化“。适用于这种情况,因为在实例化E时D不是最派生的类,所以D不会初始化A。D的构造函数不会初始化基A,并且不会使用您为D编写的初始化器。