虛函數原理解析

虛函數原理

虛函數的一般實現模型:每個類有一個虛函數表,內含該類中有作用的虛函數地址。每個 對象有一個vptr(虛函數表指針)指向虛函數表


如下Person類

class Person
{
public:
    virtual ~Person();
    virtual string& getName();
    virtual string& setName();   
protected:
    string name_;
};

在Person的對象Jack,有兩個東西,一個是數據成員name_,一個是_Vptr_Person(指向虛函數表的指針),其中_Vptr_Person存儲着以下東西:

      

如果Man集成class Person,Man如下所示:

class Man:Person
{
public:
    ~Man();
    string& getName();
    
protected:
    string hasWhat_;       //有什麼呢  哈哈
    
};
在Man對象Star中有三個東西,一個是從Person中繼承而來的name_,一個是自己的hasWhat,都是數據成員,另一個爲_Vptr_Man(虛函數表指針):

      

其中,如果Man類裏面重寫了Person類裏面的虛函數,則虛函數表被重寫函數的對應位置替換爲派生類裏面的函數地址,如Man的虛函數表中,將Person::~Person() Person::getName();的地址替換爲Man::~Man() 和Man::getName(),沒有重寫的則依舊爲基類虛函數的地址


而且,此時,Man類可作爲基類,繼續被繼承,滿足如上關係。



若派生類繼承多個具有虛函數的類,因爲需要向上類型轉換,所以派生類裏面就有多個虛函數指針。則其結構體大小會增加一個虛函數指針的大小,如下代碼所示:

class A
{
    virtual void f()
    {

    }
};

class B
{
    virtual void g();
};

class C:public B
{

};

class D:public B,public A
{

};

int main ()
{
    cout<<sizeof(A)<<endl;//A中沒有成員變量,只有一個虛函數表指針
    cout<<sizeof(B)<<endl;//同A
    cout<<sizeof(C)<<endl;//繼承了B  有一個虛函數表指針
    cout<<sizeof(D)<<endl;//繼承了A 和 B,有兩個虛函數表指針
    return 0;
}

具體輸出依賴於機器,但是滿足 sizeof(A) = sizeof(B) = sizeof(C) = sizeof(D) / 2;


   注意:虛函數指針在類中的位置,取決於編譯器具體實現,不過一般虛函數表指針的位置在類的首部,即類最開始的位置。


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