[英]C++ base class function call from last derived in diamond design
我正在學習C ++,在閱讀和測試了很多有關多重繼承,虛擬繼承/方法和鑽石設計的知識之后,直到最后我仍然有一些問題需要理解。
我處於菱形設計模式中,其中類B e C繼承virtual public A
而類D繼承public B, public C
:
A
/ \
B C
\ /
D
所有類都實現了一個私有變量std::string _message
,我使用以下字符串對其進行了初始化。
"class-name instance"
僅Class A
實現了一個virtual public display(void) const
方法。
void display(void) const{
std::cout << this->_message << std::endl;
}
主要是:
D foo;
foo.display();
輸出為:
A instance
但是,當我使用Xcode逐步“檢查”元素調試時,我發現在D實例內部,我可以正確找到一個B,一個C和A對象(B和C共享一個對象),並正確分配了所有不同的_message
。
我做錯了什么? 我需要重寫D類中的display()
方法嗎? 但是,如果是這樣,如果我必須在派生類中重新實現相同的方法,那么多重繼承的真正意義是什么?
您的問題似乎與菱形圖案無關,但通常與C ++中的繼承模型有關。 C ++中的大多數東西都是靜態綁定的,因此在編譯時,編譯器會修復使用哪種方法或某個名稱的成員:
如果訪問隱式this
對象的成員,或者使用指針或對對象的引用,那么無論在運行時是否存在派生類,最終都將在編譯時訪問指針或引用所具有的類的成員具有相同名稱成員的對象。 這就是為什么他們說,當您在派生類中定義一個相等的命名成員時,您不能覆蓋而只能覆蓋基類中的影子成員。
非虛擬功能也是如此。
唯一表現不同的是虛函數。 可以在派生類中覆蓋這些函數,並且將指針傳遞給基類的代碼可以虛化基類的功能,並最終執行派生類中給定的實現。
因此,虛函數的意義不在於讓編譯器在派生類的上下文中重新解釋某個函數(如您所理解的那樣),而是可以用一個不同的函數替換基類中的函數。派生類。
回到您的動機:如果您想要一個display
功能來打印一條消息,該消息取決於實際的對象類型,則固定的是printig,它不需要是虛擬的。 但是您需要一個虛擬函數來獲取對象類型。 像這樣:
#include <iostream>
#include <ostream>
class A {
public:
void display() { std::cout << get_message() << '\n'; }
virtual const char * get_message() { return "A instance"; }
};
class B : virtual public A {
public:
virtual const char * get_message() { return "B instance"; }
};
class C : virtual public A {
public:
virtual const char * get_message() { return "C instance"; }
};
class D : public B, public C {
public:
// virtual const char * get_message() { return B::get_message(); }
// virtual const char * get_message() { return C::get_message(); }
// virtual const char * get_message() { return "D instance"; }
};
int main(void)
{
D foo;
foo.display();
A* a_ptr = &foo;
a_ptr->display();
return 0;
}
給出的示例將無法編譯(現在這是由於菱形圖案引起的),因為編譯器無法確定A::get_message()
替代方法, B::get_message()
還是C::get_message()
在D對象中被選中后,您需要在D實代碼中進行注釋之一,以聲明D的唯一get_message
,在其中可以重用現有功能。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.