C++ 虛函數記憶體配置

來源:互聯網
上載者:User

標籤:虛函數   c++   虛函數表   記憶體配置   

    本文重點參考了《C++ 虛函數表解析》一文(連結:http://blog.csdn.net/haoel/article/details/1948051/),陳皓前輩此文講解清晰,讀後受益匪淺。只是代碼中存在一些問題,例如涉及到本文重點虛函數表的地方,寫到

Base b;cout << "虛函數表地址:" << (int*)(&b) << endl;

    但是,實際上(int*)(&b)並非虛函數表地址,而是對象b的地址,*(int*)(&b)才是虛函數表的地址。此外,後文中一些指標操作也有異常之處(也有可能是編譯環境不同?)。為此,我重新進行編碼實驗,並記錄此文。


一、實驗環境

本機作業系統Linux wm-ThinkPad-X240s 3.13.0-44-generic #73-Ubuntu SMP Tue Dec 16 00:22:43UTC 2014 x86_64 x86_64 x86_64 GNU/Linux。注意是64位機器,意味著指標長度為8位元組;如果是32位機器,則指標長度為4位元組。


    我們根據包含虛函數的類是否涉及繼承、如何繼承,分單個類無繼承、一般繼承、多重繼承三種情況,討論虛函數的記憶體配置。

二、單個類無繼承

        我們編寫下列代碼,其中類Base包含三個虛函數。

#include <iostream> using namespace std; class Base {public:    virtual void f() { cout << "Base::f" << endl; }    virtual void g() { cout << "Base::g" << endl; }    virtual void h() { cout << "Base::h" << endl; }}; typedef void (*Fun) (); int main() {    Base b;    Fun pFun = NULL;     cout << "sizeof(b): " << sizeof(b) << endl;     cout << "對象的地址: " << (&b) << endl;    cout << "虛函數表的地址: " << *(int*)(&b) << endl;     pFun = (Fun)(*(int*)(*(int*)(&b)));    pFun();     pFun = (Fun)(*(int*)(*(int*)(&b) + 8));    pFun();     pFun = (Fun)(*(int*)(*(int*)(&b) + 16));    pFun();     return 0;}


運行結果為

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/71/A2/wKiom1XVV3SjC2nlAADKd3l7ftA359.jpg" title="1.png" alt="wKiom1XVV3SjC2nlAADKd3l7ftA359.jpg" />

根據運行結果可知,對象b的記憶體規模為8位元組,這8位元組為儲存虛函數表指標所佔用(64位機器,指標8位元組)。

這裡順便說一些C++類中與虛函數無直接關係的記憶體配置知識,如果沒有虛函數,則類和對象的所佔記憶體為類中資料成員的記憶體量(需要考慮對齊),類中函數成員不佔記憶體量。那麼如果一個類沒有資料成員和虛函數,對其求sizeof,結果應當是多少呢?結果本來應當是0,但是一個執行個體它必須在記憶體中佔有一定的空間,因此實際結果為1。《劍指offer》中就有類似的題目,有興趣的朋友可以自行實驗。

根據代碼及其運行結果,我們可以推斷出其記憶體配置如所示。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M02/71/9F/wKioL1XVXJeCUhG7AAHEaKD_Jy4088.jpg" title="V1.png" alt="wKioL1XVXJeCUhG7AAHEaKD_Jy4088.jpg" />


三、一般繼承

        我們編寫下列代碼,其中Base為基類, Derive繼承Base類。

#include <iostream> using namespace std; class Base {public:    virtual void f() { cout << "Base::f" << endl; }    virtual void g() { cout << "Base::g" << endl; }    virtual void h() { cout << "Base::h" << endl; }}; class Derive : public Base {public:    void f() { cout << "Derive::f" << endl; }    virtual void g1() { cout << "Derive::g1" << endl; }    virtual void h1() { cout << "Derive::h1" << endl; }}; typedef void (*Fun) (); int main() {    Derive d;    Fun pFun = NULL;     cout << "sizeof(d): " << sizeof(d) << endl;    cout << "對象的地址: " << (&d) << endl;    cout << "虛函數表的地址: " << *(int*)(&d) << endl;     pFun = (Fun)(*(int*)(*(int*)(&d)));    pFun();     pFun = (Fun)(*(int*)(*(int*)(&d) + 8));    pFun();     pFun = (Fun)(*(int*)(*(int*)(&d) + 16));    pFun();     pFun = (Fun)(*(int*)(*(int*)(&d) + 24));    pFun();     pFun = (Fun)(*(int*)(*(int*)(&d) + 32));    pFun();     return 0;}

運行結果為

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/71/A2/wKiom1XVWvyAbppoAADoBPPPuzQ059.jpg" title="2.png" alt="wKiom1XVWvyAbppoAADoBPPPuzQ059.jpg" />

根據代碼及其運行結果,我們可以推斷出其記憶體配置如所示。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/71/9F/wKioL1XVXSDSpDtpAAG4RRuf_BQ431.jpg" title="V2.png" alt="wKioL1XVXSDSpDtpAAG4RRuf_BQ431.jpg" />


四、多重繼承

        我們編寫下列代碼,類Derive繼承類Base1、Base2、Base3。

#include <iostream> using namespace std; class Base1 {public:    virtual void f() { cout << "Base1::f" << endl; }    virtual void g() { cout << "Base1::g" << endl; }    virtual void h() { cout << "Base1::h" << endl; }}; class Base2 {public:    virtual void f() { cout << "Base2::f" << endl; }    virtual void g() { cout << "Base2::g" << endl; }    virtual void h() { cout << "Base2::h" << endl; }}; class Base3 {public:    virtual void f() { cout << "Base3::f" << endl; }    virtual void g() { cout << "Base3::g" << endl; }    virtual void h() { cout << "Base3::h" << endl; }}; class Derive : public Base1, public Base2, public Base3 {public:    void f() { cout << "Derive::f" << endl; }    virtual void g1() { cout << "Derive::g1" << endl; }    virtual void h1() { cout << "Derive::h1" << endl; }}; typedef void(*Fun)(void); int main() {    Derive d;    Fun pFun = NULL;    int** pVtab = (int**)&d;     cout << "sizeof(b): " << sizeof(d) << endl;     pFun = (Fun)pVtab[0][0];    pFun();     pFun = (Fun)pVtab[0][2];    pFun();     pFun = (Fun)pVtab[0][4];    pFun();     pFun = (Fun)pVtab[0][6];    pFun();     pFun = (Fun)pVtab[0][8];    pFun();     pFun = (Fun)pVtab[1][0];    pFun();     pFun = (Fun)pVtab[1][2];    pFun();     pFun = (Fun)pVtab[1][4];    pFun();     pFun = (Fun)pVtab[2][0];    pFun();     pFun = (Fun)pVtab[2][2];    pFun();     pFun = (Fun)pVtab[2][4];    pFun();     return 0;}

運行結果

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M01/71/A2/wKiom1XVW17icx1QAADnJINvDxs178.jpg" title="3.png" alt="wKiom1XVW17icx1QAADnJINvDxs178.jpg" />

根據代碼及其運行結果,我們可以推斷出其記憶體配置如所示。

650) this.width=650;" src="http://s3.51cto.com/wyfs02/M00/71/9F/wKioL1XVXfDDdf3VAALywYTDdCA501.jpg" title="V3.png" alt="wKioL1XVXfDDdf3VAALywYTDdCA501.jpg" />

本文出自 “說話的白菜” 部落格,謝絕轉載!

C++ 虛函數記憶體配置

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.