C++中的虛函數

C++中的虛函數

引言

C++中的虛函數,是實現C++多態的一個重要手段。這裏會介紹一下虛函數和RTTI。


一、虛函數表和虛函數表的指針

要了解C++是如何實現虛函數這功能,首先我們就要了解一個重要概念:虛函數表(Virtual Tables,之後簡稱vtbls)。

虛函數表是類額外的一個靜態數組。其中存放該類的虛函數信息等。

在編譯的時候,編譯器同時也會爲基類創建一個成員變量:用於存放類對象的虛擬表的位置(virtual Table Pointers,之後簡稱vptrs)。

下面舉一個例子來解釋虛函數表。

class CBase
{
public:
    virtual void f1();
    virtual void f2(int i);
    void f3(const char * p);
};
class CSub1 : publicCBase
{
public:
    virtual void f1();
};
class CSub2 : publicCBase
{
public:
    virtual void f2(int i);
};
 
int _tmain(int argc,_TCHAR* argv[])
{
    CBase * p1 = newCSub1();
    p1->f1();
    p1->f2(1);
    delete p1;
 
    CBase * p2 = newCSub2();
    p2->f1();
    p2->f2(1);
    delete p2;
 
    return 0;
}
下圖便是其中虛函數表的具體情況
圖1.1

在程序中,new CSub1(),系統爲這個new出來的對象的創建一個數組,存放了CSub1對象的虛函數信息,並且將這個數組的地址賦值給該對象的vptrs

接下來將CSub1對象的地址付給了指針p1。而這個指針的類型是CBase*,但是它所指向的對象卻是CSub1

當執行語句p1->f1()的時候,利用指針找到內存中的CSub1對象,隨後再通過該對象的vptrs找到CSub1對象的虛函數表,在表中找到了虛函數f1實現的地址,找到真正的f1函數。可以看圖1.1,CSub1的f1所指向的是CSub1自己的類成員函數f1。

當執行語句p1->f2(1)的時候,和上面的步驟一樣,最終找到了CBasef2

同樣p2指針也類似,這裏就不做累述。


二、RTTI

Run-Time Type Information,在程序運行時,能夠判斷一個對象的類型。承接上一節提到的靜態類型和動態類型。

void deal(CBase * p);
……
deal(new CSub1());

這裏作爲函數deal的參數p的靜態類型是CBase*,這是在編譯器進行編譯的時候,能夠判斷的類型。但是,如果我們將CBase的子類CSub1的對象的指針作爲參數給p賦值後,p的動態類型便是CSub1。所謂動態類型便是在程序運行的時候,對象實際的類型。這就是RTTI要做得事。

 

對於RTTI,其中介紹兩個個操作。

(1)dynamic_cast,用於多態類型的轉換。經常被用來將基類對象的指針轉換成子類對象的指針。

比如:

CBase * p = newCSub1();
CSub1 * ps1 = p;//1
CSub1 * ps1 =dynamic_cast<CSub1 *>(p); //2

上面第一種轉換,編譯器是無法通過的,但是第二種轉換編譯是沒有問題的。

 

(2)typeid,用於確定對象的精確類型。記住這裏是對象的類型,傳入一個指針,它只會去判斷這個指針的類型,而不是這個指針指向對象的類型。

CBase * p1 = newCSub1();
CBase * p2 = newCSub2();
CBase * p = newCBase();
cout<<"typeid(p).name():"<<typeid(p).name()<<endl;
cout<<"typeid(p1).name():"<<typeid(p1).name()<<endl;
cout<<"typeid(p2).name():"<<typeid(p2).name()<<endl;
cout<<"typeid(*p).name():"<<typeid(*p).name()<<endl;
cout<<"typeid(*p1).name():"<<typeid(*p1).name()<<endl;
cout<<"typeid(*p2).name():"<<typeid(*p2).name()<<endl;
delete p1;
delete p2;
delete p;

這裏的輸出便是:


其實typeid這個操作返回的類型是type_info(這裏就不再做介紹了)。


三、總結

在C++中利用虛函數,可以實現很多面向對象的模式。可以在設計模式(Design Pattern)中的各處找到虛函數的影子,所以要怎麼用好虛函數,可以去參考設計模式。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章