2016-07-19 83 views
1

這是我在閱讀this section on learncpp.com時遇到的問題。我使用了這裏列出的代碼,然後對測試做了輕微的改動。用C++虛擬繼承期間調用構造函數

背景

虛繼承創建一個共同的參考基類,其具有兩個效果。首先,它消除了歧義,因爲只有一次創建基本成員的副本(例如,向PoweredDevice添加print()函數並在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; 
} 
+2

你做了什麼「輕微的改動」?無論如何,你應該在這裏發佈代碼 – user463035818

+2

歡迎來到堆棧溢出!請** [編輯] **用[mcve]或[SSCCE(Short,Self Contained,Correct Example)](http://sscce.org)的問題 – NathanOliver

+0

在編輯中添加了代碼。我檢查過的變體包括基類中的成員值和函數,包括不同的訪問說明符。我也嘗試改變虛擬繼承訪問級別。 –

回答

7

這似乎是一個錯誤的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都能夠正確編譯原始代碼,並給出預期的輸出。

+0

這工作。謝謝! –

+2

@RyanB不客氣。如果您想檢查特定編譯器中的某個錯誤或語言問題,通常可以使用聯機環境來編譯您尚未安裝的編譯器。我喜歡[Rextester](http://www.rextester.com/),它的下拉菜單中有Clang,GCC和VC++。不過,每個人都在一個單獨的頁面上,因此您應該在切換到其他頁面之前複製您的代碼。 –

+0

有沒有人爲此提出過錯誤?否則,我們將不得不忍受痛苦。 –