<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》
    主站蜘蛛池模板: 亚洲日韩精品一区二区三区 | 黄色成人免费网站| 亚洲人成图片小说网站| kk4kk免费视频毛片| 亚洲国产精品尤物YW在线观看| 精品在线视频免费| 免费在线观看中文字幕| 日本黄页网址在线看免费不卡| 亚洲av无码成人精品区| 一二三区免费视频| 亚洲欧洲日产国码av系列天堂| 免费国产99久久久香蕉| 久久精品国产亚洲AV大全| 亚洲免费福利视频| 亚洲最大av资源站无码av网址| 毛片a级毛片免费播放100| 大桥未久亚洲无av码在线| 亚洲男人天堂2020| 久久久久国产精品免费看| 亚洲熟妇无码久久精品| 成全高清视频免费观看| 添bbb免费观看高清视频| 在线观看亚洲成人| 3d动漫精品啪啪一区二区免费| 2017亚洲男人天堂一| 国产一精品一aⅴ一免费| 中文字幕免费在线看线人动作大片 | 丁香花免费完整高清观看| 亚洲成AV人片高潮喷水| 国产亚洲成人久久| 最近2018中文字幕免费视频| 学生妹亚洲一区二区| 亚洲国产成人久久一区WWW| 性无码免费一区二区三区在线| 中国china体内裑精亚洲日本| 免费国产成人高清视频网站| 大地资源中文在线观看免费版 | 亚洲欧洲中文日韩av乱码| 免费A级毛片av无码| 最新亚洲人成无码网站| 亚洲好看的理论片电影|