2012-03-28 186 views
62

我不明白爲什麼在下面的代碼中,當我instanciate類型爲daughter的對象時,默認的grandmother()構造函數被調用?爲什麼在虛擬繼承中調用Default構造函數?

我認爲應該調用grandmother(int)構造函數(遵循我的mother類構造函數的規範),或者由於虛擬繼承,此代碼根本不應編譯。

這裏編譯器在我的後面默默地調用grandmother默認構造函數,而我從來沒有要求它。

#include <iostream> 

class grandmother { 
public: 
    grandmother() { 
     std::cout << "grandmother (default)" << std::endl; 
    } 
    grandmother(int attr) { 
     std::cout << "grandmother: " << attr << std::endl; 
    } 
}; 

class mother: virtual public grandmother { 
public: 
    mother(int attr) : grandmother(attr) { 
     std::cout << "mother: " << attr << std::endl; 
    } 
}; 

class daughter: virtual public mother { 
public: 
    daughter(int attr) : mother(attr) { 
     std::cout << "daughter: " << attr << std::endl; 
    } 
}; 

int main() { 
    daughter x(0); 
} 
+0

什麼編譯器(和版本)?你用什麼論據來編譯它? – orlp 2012-03-28 12:46:43

+0

gcc 4.6.3 20120306(Red Hat 4.6.3-2)on fedora 15.參數是:-O0 -g3 -Wall -c -fmessage-length = 0 – 2012-03-28 12:47:29

+0

g ++ 4.1.2有同樣的問題:http:// codepad.org/L0jBXfSP – orlp 2012-03-28 12:49:57

回答

66

當使用虛擬繼承時,虛擬基類的構造函數被大多數派生類的構造函數直接調用。在這種情況下,構造函數daughter直接調用grandmother構造函數。

由於您沒有明確地在初始化列表中調用grandmother構造函數,因此將調用默認的構造函數。要調用正確的構造函數,將其更改爲:

daugther(int attr) : grandmother(attr), mother(attr) { ... } 

又見This FAQ entry

+2

完全合理,謝謝!層次結構中的所有構造函數都從最後一個類中調用,而不是由它們各自的子類調用。從來沒有想到這一點。 C++規範有時可能會很棘手... – 2012-03-28 13:03:27

+0

謝謝!所以在虛擬繼承的情況下,最好做的是手動調用鏈中的所有構造函數。 – 2012-03-28 13:11:21

+0

優秀的答案!謝謝! – 2013-05-30 15:11:41