C++遲後聯編和虛函數表

先看一個題目:數組

class Base
{
public:
    virtual void Show(int x)
    {
        cout << "In Base class, int x = " << x << endl;
    }
};

class Derived : public Base
{
public:
    virtual void Show(float x)
    {
        cout << "In Derived, float x = " << x << endl;
    }
};

void test (Base &b)
{
    int i = 1;
    b.Show(i);
    
    float f = 2.0;
    b.Show(f);
}

int main(int argc, char *argv[])
{
    Base bc;

    Derived sc;
    test(bc);
    test(sc);
 
    return 0;
}

輸出結果爲:D

A、In Base class, int x = 1;
   In Base class, int x = 2;
   In Derived, int x = 1;
   In Derived, float x = 2;
B、In Base class, int x = 1;
   In Base class, int x = 2;
   In Derived, float x = 1;
   In Derived, float x = 2;
C、In Base class, int x = 1;
   In Base class, int x = 2;
   In Base, int x = 1;
   In Base, float x = 2;
D、In Base class, int x = 1;
   In Base class, int x = 2;
   In Base class, int x = 1;
   In Base class, int x = 2;

理由:若是虛函數在基類與子類中出現的僅僅是名字的相同,而參數類型不一樣,或者返回類型不一樣,即便寫上了virtual關鍵字,也不進行遲後聯編。ide

stackoverflow上,能夠看到解釋,http://stackoverflow.com/questions/27227189/override-virtual-function-with-different-parameters-in-c函數

C++裏有兩種編譯類型:
1) 先期聯編或靜態聯編:在編譯時就能進行函數聯編稱爲先期聯編或靜態聯編。
2) 遲後聯編或動態聯編:在運行時才能進行的聯編稱爲遲後聯編或動態聯編。spa

virtual關鍵字的做用就是提示編譯器進行遲後聯編,告訴連接過程:「我是個虛的,先不要鏈接我,等運行時再說」。 具體原理:當編譯器遇到virtual後,會爲所在的類構造一個表和一個指針,那個表叫作vtbl,每一個類都有本身的vtbl,vtbl的做用就是保存本身類中虛函數的地址,咱們能夠把vtbl形象地當作一個數組,這個數組的每一個元素存放的就是虛函數的地址,指針叫作vptr,指向那個表。而這個指針保存在相應的對象當中,也就是說只有建立了對象之後才能找到相應虛函數的地址。 .net

對於下面這種常見代碼(假如Base是Derive的父類):指針

Base *p=new Derive();
p->virtual_fun();

在程序運行時,根據對象的類型去初始化vptr,從而讓vptr正確的指向所屬類的虛表。上述程序中,因爲p實際指向的對象類型是Derive,所以vptr指向的Derive類的vtable,當調用p->virtual_fun()時,根據虛表中的函數地址找到的就是Derive類的virtual_func()函數。code

 

假設咱們有這樣的一個類:對象

class Base {

     public:

            virtual void f() { cout << "Base::f" << endl; }

            virtual void g() { cout << "Base::g" << endl; }

            virtual void h() { cout << "Base::h" << endl; }

};

對應的虛函數表:blog

假設有以下所示的一個繼承關係:繼承

對於實例:Derive d; 的虛函數表以下:

若是是多繼承:

對於實例:Derive d; 的虛函數表以下:

而C++標準規定:爲確保運行時的多態定義的基類與派生類的虛函數不只函數名要相同,其返回值及參數都必須相同,不然即便加上了virtual,系統也不進行遲後聯編。

所以,對於最初的題目,Base的虛函數表裏僅僅有一個Show方法,因爲Derived子類重載了Show函數,那麼Derived的虛函數表裏實際上有兩個Show方法,

所以,從Base角度去調用Show方法也只能是調用Base本身的方法了。

 

虛函數表的例子參考了:http://blog.csdn.net/haoel/article/details/1948051

相關文章
相關標籤/搜索