[英]How polymorphism works involving multiple inheritance?
我正在研究與多重繼承相關的主題。 我提出了以下代碼,但無法完全弄清其背后的機制:
struct root
{
virtual void vfunction(){ /* root version */ }
};
struct mid1:public root
{
virtual void vfunction(){ /* mid1 version */ }
};
struct mid2:public root
{
virtual void vfunction(){ /* mid2 version */ }
};
struct inheritMulti:public mid1, public mid2
{
void ambiguityMethod(){
vfunction(); // error: ambiguous
}
void method1(){
mid1& t = *this;
t.vfunction();
}
void method2(){
mid2& t = *this;
t.vfunction();
}
};
顯然, ambiguityMethod
是一個錯誤。 然而,函數調用這兩個method1
和method2
搞糊塗了。 它們也是虛擬函數調用,並且t
實際上是inheritMulti
類型。 所以他們應該叫inheritMulti
版本vfunction
,但由於inheritMulti
沒有它自己的版本,我不知道會發生什么。 結果表明method1
調用調用了mid1
版本,而method2
調用調用了mid2
版本。 它是未定義的東西,只發生在我的編譯器上嗎? 如果沒有,為什么它會這樣工作? vtable如何處理這種情況? 謝謝!
首先感謝您的幫助。 我自己搜索過有關主題的文章,所以,我知道“鑽石問題”。 但我認為我的問題與此不同。 我最關心的是“虛函數調用”的行為是否method1
和method2
明確定義或標准定義的。 在編譯器中,它的行為類似於我上面提到的,但是標准所承諾的行為是嗎? 如果定義明確,為什么要分別調用mid1
和'mid2'版本? (直覺的想法是調用t
的inheritMulti
版本,因為t
的類型實際上是inheritMulti
)而且,大多數編譯器如何處理這種情況? 這是奇怪的是,在虛擬函數調用method1
和method2
調用不同的功能。 再次感謝!
虛擬關鍵字根本不在此處播放。
當兩個類的函數具有相同的名稱,而第三個類都從它們繼承時,則在使用范圍運算符::
調用該函數時,需要手動指定要引用的基類。
void ambiguityMethod(){
mid1::vfunction();
}
要么
void ambiguityMethod(){
mid2::vfunction();
}
要么
void ambiguityMethod(){
root::vfunction();
}
與t:(警告:奇怪的語法!)
t.mid1::vfunction();
您還可以重寫此函數並調用一些基類函數,從而僅指定一次調用哪個函數:
void inheritMulti::vfunction() override {
return mid1::vfunction();
}
調用vfunction
,編譯器將搜索具有相同簽名的最近的函數,並將調用此函數,而該函數又將調用mid1
函數
您的代碼描述了多重繼承中的“鑽石問題”(對於vfunction
)眾所周知的問題。 對於method1
和method2
一切都很好,因為你正在mid1
和mid2
從對象this
,並呼吁vfunction
從他們的命名空間。
void method1(){
mid1& t = *this;
t.vfunction();
}
在這里,您要調用vfunction
,該函數未在inheritMulti
定義,因此它將搜索vfunction
的最接近定義,該定義存在於mid1
。 請參閱層次結構。
根-> Mid1-> inheritMulti
根目錄->中2->繼承多
同樣的情況
`void method2(){
mid2& t = *this;
t.vfunction();
}
在這里,在mid2中也找到了最接近的定義,因此得到了輸出。 這些調用不是模棱兩可的,因為兩個結構都在其中創建了自己的vfunction
副本。
inheritMulti
將有兩個名為mid1
和mid2
的子對象,並且這些子對象中的每一個都維護自己的vtable指針。 雖然您可能會認為
mid1& t1 = *this;
和mid2& t2 = *this;
t1和t2都相同,但是請嘗試這樣做...
bool same = ((void*)t1) == ((void*)t2); // Result false!
因為編譯器在后面生成一些代碼來調整指針以指向正確的對象。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.