2014-06-22 77 views
1
class A { 
public: 
    A(int) { 
     cout << "Base class" << endl; 
    } 
}; 

class B : virtual public A { 
public: 
    virtual void do_something() = 0; 
}; 

class C : public B { 
public: 
    C() 
     : A(1) { 
     cout << "C class" << endl; 
    } 

    virtual void do_something() { 
    } 
}; 

編譯器錯誤:創建用於C的對象時,編譯器產生的錯誤,如多層次繼承構造函數執行

error: no matching function for call to ‘A::A()’

爲什麼編譯器預計A級的默認構造函數?

+0

感謝上帝的鐺格式。 – chris

+0

閱讀這些概念的ISOCPP FAQ部分http://isocpp.org/wiki/faq/proper-inheritance&http://isocpp.org/wiki/faq/basics-of-inheritance –

+0

[哪個編譯器?](http ://coliru.stacked-crooked.com/a/c0d980808c205ea9) – chris

回答

1

由於沒有爲CC::C()B部分沒有明確的初始化,編譯器使用的B默認構造函數來做到這一點。

C() 
    : A(1) { 
    cout << "C class" << endl; 
} 

相當於:

C() 
    : B(), A(1) { 
    cout << "C class" << endl; 
} 

B默認構造試圖使用的A默認構造函數,它不存在初始化A一部分。這是編譯器錯誤消息。

您可以通過以下任何一種方法解決它:

  1. A提供一個默認的構造函數。
  2. B提供默認構造函數,其中使用A(int)來初始化BA部分。

更新

爲什麼編譯器要希望在B::B()A::A()?因爲它不知道,在運行時,將構建一個C的實例。

採取以下情形:

#include <iostream> 
using namespace std; 

class A 
{ 
    public: 
     A(int) 
     { 
     cout << "Came to A(int)" << endl; 
     } 
}; 

class B : virtual public A 
{ 
    public: 
     virtual void do_something(){}; 
}; 

int main() 
{ 
    B b; 
} 

很清楚爲什麼B::B()需要調用A::A(int)或期望的A::A()。由於編譯器不能,先驗,找出B是最派生的類,它必須確保有一種方法來從B初始化A,如有必要。

+0

大多數派生類負責'A'子對象的初始化,因爲它實際上是繼承的。 – chris

+0

找到引用(§10.1[class.mi]/4):*對於指定爲虛擬的每個不同的基類 ,派生最多的對象應包含該類型的單個基類子對象* – chris

+0

@chris,我同意你在說什麼。這仍然留下了問題:「B」如何初始化?這就是OP的代碼出現編譯器錯誤的地方。 –

0

B沒有默認的構造函數。

B沒有用戶定義的默認構造函數,編譯器提供的默認構造函數會形成不良的,因爲它必須使用A默認的構造函數,並A現在沒有。

即使B默認的構造函數不應該調用A構造函數時B作爲基類,你仍然需要B有效的默認構造函數,如果你想使用它。

0

這是問題的明細,在C++ 11:

  • 由於存在用於B沒有用戶聲明的構造,沒有參數的構造被隱式地聲明爲缺省值。但是,由於A沒有默認構造函數,所以此構造函數是,其定義爲刪除。 Ref [class.ctor]#5。 (這實際上意味着B永遠不會被創建,因爲它沒有未刪除的構造函數)。

  • C的構造函數在其初始化程序列表中沒有提及B,因此B子對象是默認初始化的。 Ref [class.base.init]#8

  • 默認初始化一個沒有可訪問默認構造函數的對象意味着該程序不合格。參考[dcl.init]#6

有在[class.base.init]#8的條款,一個基類不需要構造如果它是一個虛基類的抽象類的。但是,這不是這種情況。 A是這樣一類,但B不是。

摘要 - CB子對象沒有有效的構造函數。