輸出:
sizeof(d) = 8
using pa to call funca()...
basea::funca()
using pb to call funcb()...
baseb::funcb()
using pbc to call funcb()...
baseb::funcb()
using pbe to call funcb()...
basea::funca()
分析:1. sizeof(d) = 8 ==> d 中包含兩個虛函式表指標
2. dynamic_cast(pa); 編譯器做了什麼?
由於使用了 dynamic_cast 關鍵字,編譯器會檢查 pa 指標指向的物件d。
檢視 d 物件存在父類 basea, baseb, 於是判定dynamic_cast(pa);的強制型別轉換合法。
在強制型別轉換時,對指標做乙個修正,使得 pbe 指向 pb 所指的位置。
3. baseb* pbe = (baseb*)pa; pbe->funcb();
basea 型別指標 pa 指向 d 物件,將 pa 賦值給 baseb 型別,「等價於」將 d 物件位址賦值給 pbe 指標。
那麼使用 baseb 型別指標 pbe 呼叫 funcb(), 為什麼 basea 類中的 funca() 會被呼叫呢?
類 basea 與 類 baseb 定義的成員結構相同,那麼生成的虛函式表結構也將相同;
funca() 與 funcb() 是虛函式,那麼函式的呼叫將通過虛函式表指標完成;
baseb* pbe = (baseb*)pa; ==> c 方式的強制型別轉換將導致 pbe 指標指向 pa 指標指向的位址;
pbe->funcb(); ==> 實際將在 pa 指標指向處查詢虛函式表指標vptr, 因為條件1,於是在 vptr1 指標指向的虛函式表中查詢到 funca() 並成功呼叫。
單繼承某個類 + 實現( 多個 ) 介面
表象是多繼承,但在物件導向語義中已不再是多繼承(僅繼承自乙個類,其它類都是介面)
#include using namespace std;
class base
int geti()
bool equal(base* obj) // 注意這裡
};class inte***ce1
;class inte***ce2
;class derived : public base, public inte***ce1, public inte***ce2
void add(int i)
void minus(int i)
void multiply(int i)
void divide(int i)
}};int main()
輸出:
p->geti() = 100
p->geti() = 40
pint1 == p : 1
pint2 == p : 1
53 被遺棄的多重繼承
c 支援編寫多重繼承的 乙個子類可以擁有多個父類,子類擁有所有父類的成員變數,子類繼承所有父類的成員函式,子類物件可以當作任意父類物件使用。多重繼承的本質與單繼承相同。include include using namespace std class basea int geta class bas...
類的繼承 被遺棄的多重繼承
本文參照於狄泰軟體學院,唐佐林老師的 c 深度剖析教程 關聯知識 virtual虛函式,繼承 問題 c 中是否允許乙個類繼承自多個父類?如果可以,那麼會出現什麼問題呢?如果不可以,為什麼?我們在單繼承的語法基礎上,再繼承兩個父類,試試編譯是否能通過。class derived public base...
C 53 被遺棄的多重繼承 (上)
問題 c 中是否允許乙個類繼承自多個父類?class derived public base a,public base b,public base c include using namespace std class basea int geta class baseb int getb cla...