1、多型
多型是物件導向程式的核心概念。c++的多型實現是基於繼承和虛函式,這種實現稱為動態多型性。多型性可以簡單的概括為「1個介面,多種方法」,在程式執行的過程中才決定呼叫的機制,簡單的說就是可以通過父類指標呼叫子類的函式,可以讓父類指標有多種形態。
2、問題引入
先看下面幾個問題:
//code sample1
class a
};class b :public a
};int main(void)
};class b:public a
};int main(void)
};class b:virtual public a
};int main(void)
virtual void funca(){}
virtual void func()
}; classb : public a
virtual void funcb(){}
virtual void func()
}; int main(void)
輸出的結果是:class b's func.
多型就是多種狀態,乙個事物可能有多種表現形式,譬如動物,有十二生肖甚至更多的表現形式。當基類裡實現了某個虛函式,但派生類沒有實現,那麼類 b 的例項裡的虛函式表中放置的就是 &a::func。此外,派生類也實現了虛函式,那麼類 b 例項裡的虛函式表中放置的就是 b::func。a *pa = new b; 因為 b 實現了 func,那麼它被放入 a 例項的虛函式表中,從而代替 a 例項本身的虛函式。pa->func(); 呼叫的結果就不稀奇了,這是虛函式機制帶來的。
class a 和 class b 的記憶體布局和 vptr 可能是下面的樣子:
———-
| int a |
———-
| vptr | ——–>| &a::funca()
———- ————————————————-
| &a::func()
————————————————-
———-
| int a |
———-
| vptr | ——–>| &a::funca() 依舊是 a 的虛函式
———- ————————————————-
| int b | | &b::func() a::func()
———- ————————————————-
| &b::funcb()
————————————————-
總結一下:
4、多重繼承
class a
int a;
void fooa(){}
virtual void func();
virtual void funca()};
class b
int b;
void foob(){}
virtual void func();
virtual void funcb()};
class c : public a,public b
int c;
void fooc(){}
virtual void func();
virtual void funcc()};
int main(void)
當用基類的指標指向乙個派生類的實體地址,基類有兩種情況,一種是 class a 和 class b,如果是 a,問題容易解決,幾乎和上面單一繼承情況類似;但倘若是 b,要做位址上的轉換,情況會比前者複雜。先展現class a,b,c 的記憶體布局和 vptr:
———-
| int a |
———-
| vptr | ——–>| &a::~a()
———- ————————————————-
| &a::func()
————————————————-
| &a::funca()
————————————————-
———-
| int b |
———-
| vptr | ——–>| &b::~b()
———- ————————————————-
| &b::func()
————————————————-
| &b::funcb()
————————————————–
| &c::~c() &a::~a()
———- ————————————————-
| int a | | &c::func() &a::func()
———- ————————————————-
———- | &c::funcc()
| vptr | ——–>————————————————-
———- | &a::funca()
———- ————————————————-
| int b | | &b::funcb() 跳
———- ————————————————-
———-
| vptr | ——–>| &c::~c() &b::~b() 跳
———- ————————————————-
| int c | | &c::func() &b::func() 跳
———- ————————————————-
| &b::funcb()
多重繼承中,會有保留兩個虛函式表,乙個是與 a 共享的,乙個是與 b 相關的,他們都在原有的基礎上進行了修改:
對於 a 的虛函式表:
對於 b 的虛函式表:
int main(void)
輸出結果是:
c func.
c func.
funcc.
c destruction
b destruction
a destruction
c destruction
b destruction
a destruction
c destruction
b destruction
a destruction
7 行和 8 行的行為有很大的區別,7 行的呼叫和上面的單一繼承的情況類似,不贅述。8 行的 pb->func(); 中,pb 所指向的是上圖第 9 行的位置,編譯器已在內部做了轉換,也就是 pa 和 pb 所指的位置不一樣,pa 指向的是上圖第 3 行的位置。接著需要注意的是,pb->func(); 呼叫時,在虛函式表中找到的位址需要再進行一次跳轉,目標是 a 的虛函式表中的 &c::func(),然後才真正執行此函式。所以,上面的情況作了指標的調整。
那什麼時候會出現跳,常見的有兩種情況:
右端基類,對應上面的具體是 b,呼叫派生類虛函式,比如 pb->~c() 和 pb->func()
派生類呼叫右端基類的虛函式,比如 pc->funcb()
所以 delete pa; 和 delete pa; 的操作是不一樣的,pb->funcb(); 和 pc->funcb(); 也不一樣。
c++ 為實現多型引入虛函式機制,帶來了空間和執行上的折損。
C 多型的實現機制深入理解
1.用virtual關鍵字申明的函式叫做虛函式,虛函式肯定是類的成員函式。2.存在虛函式的類都有乙個一維的虛函式表叫做虛表。類的物件有乙個指向虛表開始的虛指標。虛表是和類對應的,虛表指標是和物件對應的。3.多型性是乙個介面多種實現,是物件導向的核心。分為類的多型性和函式的多型性。4.多型用虛函式來實...
深入理解Java多型機制
目錄 1,多型的概念?2,存在的條件?3,案列解析?4,應用場景?1,多型的概念 父類引用指向子類物件,通俗點就是,在編譯時不繫結是什麼方法,根據你傳進來的值,是什麼就會執行什麼。2.存在條件 第一,要有繼承 第二,要有方法的重寫 第三,父類引用指向子類物件 3,案列解析 好好體會以下這個案例,通過...
深入理解c 多型實現原理
多型是指通過基類的指標或者引用,在執行時動態呼叫實際繫結物件函式的行為。與之相對應的編譯時繫結函式稱為靜態繫結。多型是物件導向程式設計的核心思想之一,因此我們有必要深入探索一下它的實現原理。理解了原理才能更好的使用。前置條件 現有 如下所示,非常簡單的例子。通過基類的引用呼叫recv函式來觸發多型。...