在面試過程中C++的多態實現機制經常會被面試官問道。大家清楚多態到底該如何實現嗎?下面小編抽空給大家介紹下多態的實現機制。
1. 用virtual關鍵字申明的函數叫做虛函數,虛函數肯定是類的成員函數。
2. 存在虛函數的類都有一個一維的虛函數表叫做虛表。類的對象有一個指向虛表開始的虛指針。虛表是和類對應的,虛表指針是和對象對應的。
3. 多態性是一個接口多種實現,是面向對象的核心。分為類的多態性和函數的多態性。
4. 多態用虛函數來實現,結合動態綁定。
5. 純虛函數是虛函數再加上= 0。
6. 抽象類是指包括至少一個純虛函數的類。
多態的簡單介紹
一般來說,多態分為兩種,靜態多態和動態多態。靜態多態也稱編譯時多態,主要包括模板和重載。而動態多態則是通過類的繼承和虛函數來實現,當基類和子類擁有同名同參同返回的方法,且該方法聲明為虛方法,當基類對象,指針,引用指向的是派生類的對象的時候,基類對象,指針,引用在調用基類的方法,實際上調用的是派生類方法。這就是動態多態。
靜態多態的實現
靜態多態靠編譯器來實現,簡單來說就是編譯器對原來的函數名進行修飾,在c語言中,函數無法重載,是因為,c編譯器在修飾函數時,只是簡單的在函數名前加上下劃線"_" 。而c++編譯器不同,它根據函數的類型,個數來對函數名進行修飾,這就使得函數可以重載,同理,模板也是可以實現的,針對不同類型的實參來產生對應的特化的函數,通過增加修飾,使得不同的類型參數的函數得以區分。
以下段程序為例
#include <iostream>using namespace std;template <typename T1, typename T2>int fun(T1 t1, T2 t2){}int foofun(){}int foofun(int){}int foofun(int , float){}int foofun(int , float ,double){}int main(int argc, char *argv[]){fun(1, 2);fun(1, 1.1);foofun();foofun(1);foofun(1, 1.1);foofun(1, 1.1, 1.11);return 0;}
經過編譯之后:
只選取main函數部分來看:
可以發現,調用的函數名均發生了變化,都加了相應的修飾,使得調用的函數是不一樣的,靜態多態就是如此。
動態多態的實現
聲明一個類時,如果類中有虛方法,則自動在類中增加一個虛函數指針,該指針指向的是一個虛函數表,虛函數表中存著每個虛函數真正對應的函數地址。動態多態采用一種延遲綁定技術,普通的函數調用,在編譯期間就已經確定了調用的函數的地址,所以無論怎樣調用,總是那個函數,但是擁有虛函數的類,在調用虛函數時,首先去查虛函數表,然后在確定調用的是哪一個函數,所以,調用的函數是在運行時才會確定的。
在聲明基類對象時,虛函數表中綁定的就是基類的方法的地址。在聲明派生類對象時,虛函數表中綁定的就是派生類的方法。在對象被創建之后(以指針為例),無論是基類指針還是派生類指針指向這個對象,虛函數表是不會改變的。
以下段程序為例:
#include <iostream>using namespace std;class Base{public:virtual void fun(){cout << "this is base fun" << endl;}};class Derived : public Base{public:void fun(){cout << "this is Derived fun" << endl;}};int main(int argc, char *argv[]){Base b1;Derived d1;Base *pb = &d1;Derived *pd = (Derived *)&b1;b1.fun();pd->fun();d1.fun();pb->fun();return 0;}
運行結果如下:
從結果可以看出,當一個對象被創建之后,在調用虛函數的時候,無論是派生類指針還是基類指針指向這個對象,調用虛函數的結果是一樣的。因為,虛函數表是不變。當然,有可能在多繼承中會有多個虛函數表從而導致函數調用時調用不同的虛函數表,這里不做考慮。
以上所述是小編給大家介紹的C++多態的實現機制理解,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對VEVB武林網網站的支持!
新聞熱點
疑難解答