Visual C++對虛函數重載的詭異布局

來源:互聯網
上載者:User

    毫不令人驚訝的是,C++又給了我一個驚訝!


    對於被重載的虛函數(overloaded virtual member functions),Visual C++ 並不會依照它們聲明的順序排布在虛表中。


    一組(同名的)重載虛函數會按照它們聲明的逆序依次排布在一起,而組與組之間的順序,是由組內最先出現的那個函式宣告的位置決定的,越先聲明,該組越靠前。


    試看下面這個例子:


#include <stdio.h>


struct Base {

   virtual void a() = 0;

   virtual void b() = 0;

   virtual void a(int) = 0;

   virtual void b(int) = 0;

}; 


struct Some : public Base

{

    virtual void a() { printf("a()/n"); }

    virtual void b() { printf("b()/n"); }

    virtual void a(int) { printf("a(int)/n"); }

    virtual void b(int) { printf("b(int)/n"); }

};


int

main()

{

    Some *p = new Some;


    void (Some::*a_ptr)() = &Some::a;

    void (Some::*ai_ptr)(int) = &Some::a;

    void (Some::*b_ptr)() = &Some::b;

    void (Some::*bi_ptr)(int) = &Some::b;


    printf("%p,%p,%p,%p/n", *(void**)&ai_ptr, *(void**)&a_ptr, *(void**)&bi_ptr, *(void**)&b_ptr);


    return 0;

}


    Some對象中的vtable的順序是這樣:Some::a(int), Some::a(), Some::b(int), Some::b()。


    用VC(VS2005)跑這段程式來驗證一下,輸出是:


00401140,00401150,00401160,00401170


    COM的二進位標準要求介面方法按照聲明順序排列在虛表中,VC的做法和COM矛盾,所以不要在COM介面中使用重載虛函數。微軟的說法是,這種行為是當初VC的設計決定的,沒法兒改了,很多老代碼依賴這種行為。


    而g++在處理這個問題上的做法是符合COM規範的,當然也符合了我們的直覺,它的輸出是:


00000009,00000001,0000000D,00000005


    注意,由於不同編譯器對指向虛擬成員函數的指標的實現各有不同,所以VC和g++輸出的內容差別很大。不用去管它,我們只要給這4個值排個序就足以判斷出它們在虛表中的位置。


    最後要奉勸大家的是,即使想通過只暴露純抽象基類的方法來讓二進位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.