【摘要】多型性是物件導向程式設計語言中資料抽象和繼承之外的第三個基本特性。
要想認識多型,我們需要從最基礎的知識開始著手,這篇部落格是我整理了很久才發出來的,裡面對於多型的底層分析很詳盡,希望可以對你們有所幫助
多型的概念
多型,顧名思義就是一種事物具有多種形態,用比較正式的話來說,大概就是下面這段話啦。
向不同的物件傳送同乙個訊息,不同的物件在接收時會產生不同的行為(即方法)。也就是說,每個物件可以用自己的方式去相應共同的訊息。而所謂訊息,就是呼叫函式,不同的行為就是指不同的實現,即執行不同的函式。
粗略點來說,函式的過載和運算子過載也都算作多型,因為這類函式的一大特點就是在程式執行之前就已經確定了該呼叫哪乙個函式,這類多型稱為靜態多型,靜態多型性的函式呼叫具有呼叫速度快,效率高的優點,但是缺點就是缺乏靈活性。還有一類多型是程式在執行時才知道該呼叫那個函式,這類多型稱為執行時多型,而今天我主要分析的就是執行時多型。
多型性提供了介面和具體實現之間的另一層隔離。多型性改善了**的組織性和可讀性,同時也使得建立的程式具有可擴充套件性。
在真正認識多型之前,我希望你們可以看一下下面這段**。
class a
{public:
void f1()
{ cout<
p = &b; //讓指標重新指向子類物件b
p->f1(); //用指標呼叫f1()
這個結果肯定不是我們想要的,但是為什麼會出現這種情況呢?我用的形式給你們解釋一下
如果出現下面這種情況,就會發生隱藏的情況,先看**吧。
class a
{public:
void f1()
{ cout<
我只是在main函式裡面改了一下,程式就會出現下面的結果。
按理說,應該呼叫a的f1()吧,為什麼會呼叫b的呢?因為 f1() 函式已經構成了隱藏,而構成隱藏的情況下,派生類會隱藏基類的函式,那就會造成基類函式無法呼叫的情況。
為了解決此類情況,讓我們只需要定義乙個物件,讓它可以隨意呼叫基類或者派生類的函式呢?這就需要用到虛函式的知識了。
所謂虛函式,就是在普通函式前面加上關鍵字 virtual ,聽上去好像沒什麼難的,但是它的底層實現還是很複雜的,現在我們就來一**竟吧。
老辦法,還是剛才的那段**,我只是修改了基類函式 f1() 成為虛函式 ,得到的結果就會完全不一樣了,不行你可以試一試。
這裡我們來看一看物件 b 裡面都有什麼吧。
對了,在這裡我得先說一下,只有定義成為虛函式才會有虛函式表。每個類只有乙個虛函式表,不管這個類中定義了多少個虛函式,他們都會儲存在這張表裡面。也正是由於這張表,才使得虛函式的多型性體現出來。
接下來我們驗證一下,我上面說的對不對。驗證方法很簡單,只需要在同乙個類中定義多個函式然後用sizeof比較一下類的大小就清楚了。
最後得到的結果都是8.從上面我們已經知道,在類a中存了乙個指標指向乙個虛基表,因此占用4個位元組大小,還有本身的整型 a ,占用4個位元組,因此總共是八個位元組。並且,我們也知道了,定義虛函式就會產生虛基表,那麼這樣說的話,應該有兩個指標才對,實際上,我們從見識視窗就可以直接看到,只有乙個指標,這就間接說明了兩個虛函式都放在同乙個虛基表裡面。
現在我們已經知道了多型的實現機制,根本上就是虛函式表的應用。有了這張虛基表,我們就可以通過不同的物件呼叫不同的函式而不用擔心出現隱藏或者呼叫函式模糊的情況啦。因為這篇部落格篇幅太長了,我決定再寫一篇部落格詳細講解虛函式表的底層。
C 虛函式表剖析
為了實現c 的多型,c 使用了一種動態繫結的技術。這個技術的核心是虛函式表 下文簡稱虛表 本文介紹虛函式表是如何實現動態繫結的。每個包含了虛函式的類都包含乙個虛表。我們知道,當乙個類 a 繼承另乙個類 b 時,類a會繼承類b的函式的呼叫權。所以如果乙個基類包含了虛函式,那麼其繼承類也可呼叫這些虛函式...
C 虛函式表剖析
為了實現c 的多型,c 使用了一種動態繫結的技術。這個技術的核心是虛函式表 下文簡稱虛表 本文介紹虛函式表是如何實現動態繫結的。每個包含了虛函式的類都包含乙個虛表。我們知道,當乙個類 a 繼承另乙個類 b 時,類a會繼承類b的函式的呼叫權。所以如果乙個基類包含了虛函式,那麼其繼承類也可呼叫這些虛函式...
C 多型 虛函式 指標 虛函式表
本文總結了和幾位老師的部落格 一 什麼是多型 關於多型,簡而言之就是用父型別別的指標指向其子類的例項,然後通過父類的指標呼叫實際子類的成員函式。這種技術可以讓父類的指標有 多種形態 這是一種泛型技術。所謂泛型技術,說白了就是試圖使用不變的 來實現可變的演算法。比如 模板技術,rtti技術,虛函式技術...