[英]Invoking constructors during virtual inheritance with C++
這是我在learncpp.com上閱讀本節時遇到的一個問題。 我使用了這里列出的代碼,然后對測試做了一些改動。
背景
虛擬繼承創建對基類的公共引用,它具有兩個效果。
首先,它消除了歧義,因為只創建了一個基礎成員的副本(例如,向PoweredDevice添加print()函數並在main()中調用它否則會導致編譯器錯誤)。
其次,派生程度最高的類負責調用基礎構造函數。 如果其中一個中間類嘗試在初始化列表中調用基本構造函數,則應忽略該調用。
問題
當我編譯並運行代碼時,它返回:
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都能夠正確編譯原始代碼,並提供預期的輸出。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.