Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/wordpress/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 类派生自C++;:派生类正在尝试调用根基类构造函数_C++_Multiple Inheritance_Instantiation - Fatal编程技术网

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被实例化为最派生的对象的场景。@scozy
D::D(…):a(foo)会发生什么?
就像我在另一个答案中写的那样:“您只需知道,如果具体类不是您正在编写的类,则不一定会发生特定的初始化“。适用于这种情况,因为在实例化E时D不是最派生的类,所以D不会初始化A。D的构造函数不会初始化基A,并且不会使用您为D编写的初始化器。