所謂多型,就是「多種形態」。
在物件導向的方法中一般是這樣描述多型的:向不同的物件傳送同乙個訊息,不同的物件在接收時會產生不同的行為(即方法)。多型性的表現形式之一是:具有不同功能的函式可以用同乙個函式名,這樣就可以實現用乙個函式名呼叫不同內容的函式。
1.靜態多型
#include using namespace std;
int add(int x, int y)
float add(float x, float y)
int main()
執行結果如下:
靜態多型是通過函式過載實現的。由函式過載和運算子過載形成的多型性屬於靜態多型,要求編譯器在程式編譯時就知道呼叫函式的全部資訊。靜態多型性又稱編譯時的多型性。靜態多型性的函式呼叫速度快,效率高,但缺乏靈活性,在程式執行前就已經決定了執行的函式和方法。
2.動態多型
c++中虛函式的主要作用就是實現動態多型。簡單說父類的指標/引用呼叫重寫的虛函式,當父類指標/引用指向父類物件時呼叫的是父類的虛函式,指向子類物件時呼叫的是子類的虛函式。
虛函式:類的成員函式前面加上virtual關鍵字,則這個成員函式稱為虛函式。
虛函式的重寫:當在子類中定義了乙個與父類完全相同的虛函式時,則稱子類的這個函式重寫(覆蓋)了父類的這個虛函式。
可以看到:當把基類的某個成員函式宣告為虛函式後,允許在其派生類中對該函式重新定義,賦予它新的功能,並且可以通過指向基類的指標指向同一類族中的不同類的物件,從而呼叫其中的同名函式。
注意:由虛函式實現的動態多型性就是:同一類族中不同類的物件,對同一函式做出不同的響應。動態多型性的特點是:不在編譯時確定是哪個函式,而是在程式執行過程中動態的確定操作所針對的物件,它又稱執行時多型性。
虛析構函式:
先看如下**
程式並沒有執行派生類的析構函式。如果希望能夠執行派生類的析構函式,可以將基類的析構函式宣告為虛函式。
結論:
不加virtual關鍵字,不構成多型,此時與型別有關,指標p是父類型別,所以只呼叫父類析構函式。
加上virtual關鍵字,構成多型,此時與物件有關,會先析構子類物件,再自動呼叫父類析構函式。
建構函式不能被定義為虛函式。這是因為在執行建構函式時類物件還未完成建立過程,當然談不上把函式與類物件繫結。
靜態成員函式不能是虛函式。因為靜態成員函式的特點是不受限制於某個物件。
內聯函式不能是虛函式。因為內聯函式不能在執行中動態確定位置。
建構函式中不能呼叫虛函式。虛函式的位址是存在物件裡的,呼叫建構函式之前物件還沒初始化,及沒有虛函式,更不存在呼叫可言。
二、多型的物件模型——單繼承和多繼承
1.單繼承
多型中單繼承概念:乙個子類繼承乙個父類,子類中對父類的虛函式進行重寫,子類繼承父類的虛表之後,在此虛表中所對應虛函式儲存位置的關係。
用以下例子進行分析:
由上圖可知,子類derive繼承父類base,重寫了父類中的虛函式func1(),所以在子類的虛表中可以看到,首先存放的是,子類重寫的虛函式func1(),然後是父類的虛函式func2(),子類的虛函式func3(),最後是子類的虛函式func
()。在虛表的最後存放了乙個0作為結束標誌。
2.多繼承
多型中多繼承的概念:乙個子類繼承2個或2個以上的父類,子類中對父類的虛函式進行重寫,子類會分別繼承父類的虛表,同時分別繼承的虛表中虛函式的存放位置關係如下圖所示:
由上圖可知:乙個子類derive繼承了兩個父類,base1和base2. 同時繼承了兩個虛表,在子類物件中通過記憶體及列印函式得到,子類中有兩個虛表,繼承父類base1的虛表中存放了子類derive重寫的虛函式func1(),繼承父類base1中的虛函式func2(),以及子類derive中的虛函式func3();另乙個繼承父類base2的虛表中存放了子類derive重寫的虛函式func1(),繼承父類base1中的虛函式func2()
。同時,虛表的結束標誌是0.
三、多型的物件模型--菱形繼承和菱形虛擬繼承
1.菱形繼承
菱形繼承是幾個類的繼承關係呈菱形狀。為此,我們舉例解釋:
有類a,b,c,d。其中b,c繼承a,d繼承b,c。繼承關係圖如下:
具體**如下:
#include using namespace std;
class a
cout<
} void test()
int main()
建立乙個d類的物件d,下圖為檢視d物件中儲存的成員變數情況,以及虛表指向:
解析圖:
小結:
在普通的菱形繼承中,處於最先的d型別的物件d,它繼承了b,c,並且b,c中分別儲存了乙份來自繼承a的變數;除此之外,b,c還存了虛表指標,通過它可以找到虛表中存的虛函式位址,最後,d物件還存放了自己定義的變數和繼承b,c自己定義的變數。
菱形繼承中,建立乙個d類物件d,d中存放了b類的虛表指標及其成員_b、繼承a類的_a、c類的虛表指標及其成員_c,繼承a類的_a,以及自身的_d。
因為d類中對函式func1()進行了重寫,所以在b類的虛表中存放了d類的虛函式func1(),a類的虛函式func2(),b類的虛函式func3(),和d類的虛函式func5();
在c類的虛表中存放了d類的虛函式func1(),a類的虛函式func2(),c類的虛函式func4()。
2.菱形虛擬繼承
菱形虛擬繼承就是在普通菱形繼承的前提下加了虛繼承(本例是,b,c虛繼承a)。
建立乙個d類的物件d,下圖為檢視d物件中儲存的成員變數情況,以及虛表指向:
**如下:
#include using namespace std;
class a
cout<
} void test()
int main()
解析圖:
小結:
菱形虛擬繼承與菱形繼承的區別在於,b,c繼承a的公共成員a,既不儲存在b裡,也不儲存在c裡,而是儲存在一塊公共的部分,而會將b,c相對於這個變數的偏移位址(這裡的偏移量位址叫做虛基表)存在b,c裡。所以說,物件d裡的b,c裡存放了虛表指標,虛基表指標,自己的變數。
c 多型 多型物件模型
1.多型 在c 程式設計中,多型性是指具有不同功能的函式可以用同乙個函式名,這樣就可以用乙個函式名呼叫不同內容的函式。在物件導向方法中一般是這樣表述多型性的 向不同的物件傳送同乙個訊息,不同的物件在接收時會產生不同的行為 即方法 也就是說,每個物件可以用自己的方式去響應共同的訊息。所謂訊息,就是呼叫...
多型 多型物件模型
1 什麼多型?當使用基類的指標或引用呼叫重寫的虛函式時,指向父類調的就是父類的虛函式,指向子類調的就是子類的虛函式。下面我們來看一段 sizeof aa 的結果為什麼會是8呢?這是因為函式fun1是乙個虛函式,函式內部存在乙個虛表指標。單繼承物件模型 由於編譯器做了一定的優化,子類中自己定義的函式在...
多型 多型物件模型
一 什麼是多型。物件導向語言有三大特點,封裝 繼承 多型。今天就討論一下多型,多型是 當使用基類的指標或引用呼叫重寫的虛函式時,當指向父類呼叫的就是父類的虛函式,當指向子類就是呼叫子類的虛函式。多型 多種形態。多型分為靜態多型和動態多型。實現多型的其中乙個條件必須是要把子類給給父類,要構成is a的...