c++ - 在使用 C++ 的虚拟继承期间调用构造函数

标签 c++ constructor virtual-inheritance compiler-bug gcc5

这是我在阅读this section on learncpp.com时遇到的问题.我使用了此处列出的代码,然后为了测试做了些微改动。

背景

虚拟继承创建了对基类的公共(public)引用,这有两个作用。

首先,它消除了歧义,因为只创建了基成员的拷贝(例如,将 print() 函数添加到 PoweredDevice 并在 main() 中调用它,否则会导致编译器错误)。

其次,最派生的类负责调用基类构造函数。如果其中一个中间类试图调用初始化列表中的基本构造函数,则调用应该是 ignored .

问题

当我编译并运行代码时,它返回:

PoweredDevice: 3
PoweredDevice: 3
Scanner: 1
PoweredDevice: 3
Printer: 2

它应该返回:

PoweredDevice: 3
Scanner: 1
Printer: 2

当我使用 GDB (7.11.1) 跟踪执行时,它表明中间函数也通过初始化列表调用 PoweredDevice——但这些应该被忽略。 PoweredDevice 的多次初始化不会导致任何成员的歧义,但确实给我带来了麻烦,因为代码执行了多次,而它应该只发生一次。对于更复杂的问题,我不习惯使用虚拟继承。

为什么这些中间类还在初始化基类?是我的编译器 (gcc 5.4.0) 有问题还是我误解了虚拟继承的工作原理?

编辑:代码

#include <iostream>
using namespace std;

class PoweredDevice
{
public:
    int m_nPower;
public:
    PoweredDevice(int nPower)
        :m_nPower {nPower}
    {
        cout << "PoweredDevice: "<<nPower<<endl;
    }
    void print() { cout<<"Print m_nPower: "<<m_nPower<<endl; }
};

class Scanner : public virtual PoweredDevice
{
public:
    Scanner(int nScanner, int nPower)
        : PoweredDevice(nPower)
    {
        cout<<"Scanner: "<<nScanner<<endl;
    }
};

class Printer : public virtual PoweredDevice
{
public:
    Printer(int nPrinter, int nPower)
        : PoweredDevice(nPower)
    {
        cout<<"Printer: "<<nPrinter<<endl;
    }
};

class Copier : public Scanner, public Printer
{
public:
    Copier(int nScanner, int nPrinter, int nPower)
        :Scanner {nScanner, nPower}, Printer {nPrinter, nPower}, PoweredDevice {nPower}
    { }
};

int main()
{
    Copier cCopier {1,2,3};
    cCopier.print();
    cout<<cCopier.m_nPower<<'\n';
    return 0;
}

最佳答案

这似乎是一个 GCC 错误,当统一初始化与虚拟继承一起使用时触发。


如果我们改变:

Copier(int nScanner, int nPrinter, int nPower)
    :Scanner {nScanner, nPower}, Printer {nPrinter, nPower}, PoweredDevice {nPower}
{ }

到:

Copier(int nScanner, int nPrinter, int nPower)
    :Scanner (nScanner, nPower), Printer (nPrinter, nPower), PoweredDevice (nPower)
{ }

错误消失,并且按预期运行:

PoweredDevice: 3
Scanner: 1
Printer: 2
Print m_nPower: 3
3

Clang 和 Visual Studio 都能够正确编译原始代码,并给出预期的输出。

关于c++ - 在使用 C++ 的虚拟继承期间调用构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38466871/

相关文章:

java - JNI 和构造函数

C++ 抽象基类构造函数/析构函数 - 一般正确性

c++ - 当我们进行复制初始化时,复制构造函数或构造函数是否起作用

c++ - 应用于神经网络反向传播的交叉熵

java - 从构造函数调用阻塞方法 - Java

c++ - 在父函数中调用覆盖的子函数

c++ - 异常是否需要虚拟继承?

c++ - 如何比模板参数解析更喜欢隐式转换?

c++ - 我什么时候应该使用 std::any

c++ - 将构造函数值从子类传递到父类(super class) C++