<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    jasmine214--love

    只有當你的內心總是充滿快樂、美好的愿望和寧靜時,你才能擁有強壯的體魄和明朗、快樂或者寧靜的面容。
    posts - 731, comments - 60, trackbacks - 0, articles - 0

    C++中的虛函數(一)

    Posted on 2010-08-06 10:50 幻海藍夢 閱讀(148) 評論(0)  編輯  收藏 所屬分類: C++
    原文:http://www.vckbase.com/document/viewdoc/?id=950

        雖然很難找到一本不討論多態性的C++書籍或雜志,但是,大多數這類討論使多態性和C++虛函數的使用看起來很難。我打算在這篇文章中通過從幾個方面和結合一些例子使讀者理解在C++中的虛函數實現技術。說明一點,寫這篇文章只是想和大家交流學習經驗因為本人學識淺薄,難免有一些錯誤和不足,希望大家批評和指正,在此深表感謝!

    一、 基本概念
        首先,C++通過虛函數實現多態."無論發送消息的對象屬于什么類,它們均發送具有同一形式的消息,對消息的處理方式可能隨接手消息的對象而變"的處理方式被稱為多態性。"在某個基類上建立起來的類的層次構造中,可以對任何一個派生類的對象中的同名過程進行調用,而被調用的過程提供的處理可以隨其所屬的類而變。"虛函數首先是一種成員函數,它可以在該類的派生類中被重新定義并被賦予另外一種處理功能。

    二、 虛函數的定義與派生類中的重定義
    class 類名{
    public:
    virtual 成員函數說明;
    }
    class 類名:基類名{
    public:
    virtual 成員函數說明;
    }
    
    三、 虛函數在內存中的結構

    1.我們先看一個例子:
    #include "iostream.h"
    #include "string.h"
    class A {
    public:
    virtual void fun0() { cout << "A::fun0" << endl; }
    };
    int main(int argc, char* argv[])
    {
    A  a;
    cout << "Size of A = " << sizeof(a) << endl;
    return 0;
    }      
    結果如下:Size of A = 4

    2.如果再添加一個虛函數:virtual void fun1() { cout << "A::fun" << endl;}
    得到相同的結果。如果去掉函數前面的virtual修飾符
    class A {
    public:
    void fun0() { cout << "A::fun0" << endl; }
    };
    int main(int argc, char* argv[])
    {
    A  a;
    cout << "Size of A = " << sizeof(a) << endl;
    return 0;
    }      
    結果如下:Size of A = 1
     
    3.在看下面的結果:
    class A {
    public:
    virtual void fun0() { cout << "A::fun0" << endl; }
    int a;
    int b;
    };
    int main(int argc, char* argv[])
    {
    A  a;
    cout << "Size of A = " << sizeof(a) << endl;
    return 0;
    }      
    結果如下:Size of A = 12

    其實虛函數在內存中結構是這樣的:


    圖一

        在window2000下指針在內存中占4個字節,虛函數在一個虛函數表(VTABLE)中保存函數地址。在看下面例子。
    class A {
    public:
    virtual void fun0() { cout << "A::fun0" << endl; }
    virtual void fun1() { cout << "A::fun1" << endl; }
    int a;
    int b;
    };
    int main(int argc, char* argv[])
    {
    A  a;
    cout << "Size of A = " << sizeof(a) << endl;
    return 0;
    }
    
    結果如下:結果如下:
    Size of A = 4

        虛函數的內存結構如下,你也可以通過函數指針,先找到虛函數表(VTABLE),然后訪問每個函數地址來驗證這種結構,在國外網站作者是:Zeeshan Amjad寫的"ATL on the Hood中有詳細介紹"


    圖二

    4.我們再來看看繼承中虛函數的內存結構,先看下面的例子
    class A {
    public:
    virtual void f() { }
    };
    class B {
    public:
    virtual void f() { }
    };
    class C {
    public:
    virtual void f() { }
    };
    class Drive : public A, public B, public C {
    };
    int main() {
    Drive d;
    cout << "Size is = " << sizeof(d) << endl;
    return 0;
    }      
    結果如下:Size is = 12 ,相信大家一看下面的結構圖就會很清楚,


    圖三

    5.我們再來看看用虛函數實現多態性,先看個例子:
    class A {
    public:
    virtual void f() { cout << "A::f" << endl; }
    };
    class B :public A{
    public:
    virtual void f() { cout << "B::f" << endl;}
    };
    class C :public A {
    public:
    virtual void f() { cout << "C::f" << endl;}
    };
    class Drive : public C {
    public:
    virtual void f() { cout << "D::f" << endl;}
    };
    int main(int argc, char* argv[])
    {
    A a;
    B b;
    C c;
    Drive d;
    a.f();
    b.f();
    c.f();
    d.f();
    return 0;
    }
    結果:A::f
    B::f
    C::f
    D::f
    
    不用解釋,相信大家一看就明白什么道理!注意:多態不是函數重載

    6.用虛函數實現動態連接在編譯期間,C++編譯器根據程序傳遞給函數的參數或者函數返回類型來決定程序使用那個函數,然后編譯器用正確的的函數替換每次啟動。這種基于編譯器的替換被稱為靜態連接,他們在程序運行之前執行。另一方面,當程序執行多態性時,替換是在程序執行期進行的,這種運行期間替換被稱為動態連接。如下例子:
    class A{
    public:
    virtual void f(){cout << "A::f" << endl;};
    };
    class B:public A{
    public:
    virtual void f(){cout << "B::f" << endl;};
    };
    class C:public A{
    public:
    virtual void f(){cout << "C::f" << endl;};
    };
    void test(A *a){
    a->f();
    };
    int main(int argc, char* argv[])
    {
    B *b=new B;
    C *c=new C;
    char choice;
    do{
    cout<<"type  B for class B,C for class C:"<<endl;
    cin>>choice;
    if(choice==''b'')
    test(b);
    else if(choice==''c'')
    test(c);
    }while(1);
    cout<<endl<<endl;
    return 0;
    }
    
        在上面的例子中,如果把類A,B,C中的virtual修飾符去掉,看看打印的結果,然后再看下面一個例子想想兩者的聯系。如果把B和C中的virtual修飾符去掉,又會怎樣,結果和沒有去掉一樣。

    7.在基類中調用繼承類的函數(如果此函數是虛函數才能如此)還是先看例子:
    class A {
    public:
    virtual void fun() {
    cout << "A::fun" << endl;
    }
    void show() {
    fun();
    }
    };
    class B : public A {
    public:
    virtual void fun() {
    cout << "B::fun" << endl;
    }
    };
    int main() {
    A a;
    a.show();
    return 0;
    }      
    打印結果:A::fun

        在6中的例子中,test(A *a)其實有一個繼承類指針向基類指針隱式轉化的過程。可以看出利用虛函數我們可以在基類調用繼承類函數。但如果不是虛函數,繼承類指針轉化為基類指針后只可以調用基類函數。反之,如果基類指針向繼承類指針轉化的情況怎樣,這只能進行顯示轉化,轉化后的繼承類指針可以調用基類和繼承類指針。如下例子:
    class A {
    public:
    void fun() {
    cout << "A::fun" << endl;
    }
    };
    class B : public A {
    public:
    void fun() {
    cout << "B::fun" << endl;
    }
    void fun0() {
    cout << "B::fun0" << endl;
    }
    };
    int main() {
    A *a=new A;
    B *b=new B;
    A *pa;
    B *pb;
    pb=static_cast<B *>(a); //基類指針向繼承類指針進行顯示轉化
    pb->fun0();
    pb->fun();
    return 0;
    }  
    參考資料:
    1.科學出版社 《C++程序設計》
    2.Zeeshan Amjad 《ATL on the Hood》
    主站蜘蛛池模板: 国产亚洲精品精品国产亚洲综合| 啦啦啦www免费视频| 亚洲日韩精品无码专区网址| 日韩精品免费一线在线观看| 国产又黄又爽又刺激的免费网址| 亚洲国产精品无码久久98| 韩国18福利视频免费观看| 亚洲精品无码专区在线播放| 青青草国产免费久久久91| 精品亚洲视频在线| 亚洲av高清在线观看一区二区| 美女裸体无遮挡免费视频网站| 亚洲成a人无码av波多野按摩| 一区二区三区免费在线观看| 亚洲精品二区国产综合野狼| 午夜免费福利片观看| 亚洲免费在线视频观看| 性色av免费观看| 无码 免费 国产在线观看91 | 18禁无遮挡无码国产免费网站| 亚洲黄色免费网址| 成年女人毛片免费播放视频m| 综合偷自拍亚洲乱中文字幕| 国产亚洲精久久久久久无码77777 国产亚洲精品成人AA片新蒲金 | 永久免费无码网站在线观看个| 国产亚洲精品成人AA片新蒲金| 久久精品国产影库免费看| 亚洲熟妇无码爱v在线观看| 91免费精品国自产拍在线不卡| 国产精品亚洲专一区二区三区| 国产亚洲av人片在线观看| 99re在线免费视频| 日韩欧美亚洲中文乱码| 久久亚洲免费视频| 天天看片天天爽_免费播放| aa在线免费观看| avtt天堂网手机版亚洲| 亚洲日韩精品无码专区网站| 免费无码成人AV在线播放不卡| 狼人大香伊蕉国产WWW亚洲| 久久精品亚洲综合专区|