C++的多態機制

明確以下幾點:

  1. 多態的實現是依靠虛函數表,程序需要額外的查詢虛函數表的開銷。

  2. C++的構造函數中可以調用虛函數,說明虛函數表的產生是在構造函數調用之前。虛函數表的建立是在編譯時(Compile-Time)。

    看一個例子:

    #include <iostream>
    using namespace std;
    class A
    {
        int m1;
        int m2;
    public:
        A()
        {
            fun2();
        }
        virtual void fun2()
        {
            cout<<"call A::fun2 success!"<<endl;
        }
    };
    class B:public A
    {
    public:
        B()
        {
            fun2();
        }
        void fun2()
        {
            cout<<"call B::fun2 success!"<<endl;
        }
    };
    int main()
    {
        B *pa = new B();
        return 1;
    }

    輸出結果:

    call A::fun2 success!

    call B::fun2 success!

    說明兩個構造函數內的虛函數都調用成功。由於對象的構造順序和子類對基類虛函數的重載還未完成,所以第一個fun函數是調用的A的虛函數。

    (在JAVA中會輸出兩個call B::fun2 success!,WHY??)

  3. 虛函數表的地址vptr是存在對象的this指針指向的結構體的第一個數據位置,即存儲vptr的地址和this的地址值相同。

  4. 一個類的所有對象都共享同一份虛函數表。

看一個例子:

#include <iostream>
using namespace std;
class A
{
    int m1;
    int m2;
public:
    virtual void fun2()
    {
        cout<<"call A::fun2 success!"<<endl;
    }
    void fun()
    {
        cout<<this<<' '<<&m1<<' '<<hex<<*((int*)this)<<endl;
        //*((int*)this)取vptr的值
    }
};
int main()
{
    A *pa1 = new A();
    A *pa2 = new A();
    pa1->fun();
    pa2->fun();
    return 1;
}

輸出結果:

00332BA0 00332BA4 46F01C

00332BD8 00332BDC 46F01C

兩個對象的this值不同,數據成員的地址也不同,但是其中的vptr值是相同的。


5.  雖然子類重載了基類的虛函數,但是通過子類對象依然可以訪問到基類的虛函數。

看例子:

#include <iostream>
using namespace std;
class A
{
    int m1;
    int m2;
public:
    virtual void fun2()
    {
        cout<<"call A::fun2 success!"<<endl;
    }
};
class B : public A
{
public:
    virtual void fun2()
    {
        cout<<"call B::fun2 success!"<<endl;
    }
};
int main()
{
    A *pa = new B();
    pa->A::fun2();
    return 1;
}

輸出結果:

call A::fun2() success!

也就是說,在B的虛函數表中,依然存在着A的虛函數的入口地址,而且是可以調用的。

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