探索C++與Go的介面底層實現

來源:互聯網
上載者:User
這是一個建立於 的文章,其中的資訊可能已經有所發展或是發生改變。

1、C++ 中的“介面”

C++並沒有明確的“介面”,一般約定繼承某個類,已達到介面的“實現”。

首先我們來看下單繼承的記憶體布局(<font color= Crimson size=4>依賴各廠商的實際實現,這裡僅以微軟實現為例進行說明····感謝宇宙最強IDE····</font>)

其多態主要由虛函數表(vfptr)實現 : 指標或引用調用虛函數時,在運行時由對象的虛函數表+函式宣告順序決定綁定到哪個函數上

class IDuck {public:              //嘎嘎地叫        virtual void GaGaSpeaking() = 0;                 //老爺的官步        virtual void OfficialWalking() = 0;          private:              unsigned int height;};class DonaldDuck : public IDuck { public:             void GaGaSpeaking() {               std::cout << "DonaldDuck Speak" << std::endl;        }                 void OfficialWalking() {               std::cout << "DonaldDuck Walk" << std::endl;       }     };int main(int argc, _TCHAR* argv[]){    DonaldDuck * duck = new DonaldDuck();        duck->GaGaSpeaking();             duck->OfficialWalking();             cout << "---------- hooking --------" << endl;    typedef void(*DuckFunc)();    int * addr = (int*)duck;    DuckFunc f1 = (DuckFunc)(*((int*)(*addr)));    f1();    DuckFunc f2 = (DuckFunc)(*((int*)(*addr)+1));    f2();    return 0;}

記憶體布局為:


強制調用成員函數(甚至可以是私人)


多繼承

多繼承下其實也是類似,按繼承順序依次排列,還是看程式碼範例
class IDuck {public:              //嘎嘎地叫        virtual void GaGaSpeaking() = 0;             //老爺的官步        virtual void OfficialWalking() = 0;      private:              unsigned int height;};class IActor {public:    //搞笑    virtual void MakeFun() = 0;private:    std::string Name;};class DonaldDuck : public IDuck, public IActor { public:             void GaGaSpeaking() {               std::cout << "DonaldDuck Speak" << std::endl;        }                 void OfficialWalking() {               std::cout << "DonaldDuck Walk" << std::endl;       }         void MakeFun() {        std::cout << "Wa HAHAHA ~~~" << endl;    }};int main(int argc, _TCHAR* argv[]){    DonaldDuck * duck = new DonaldDuck();        duck->GaGaSpeaking();             duck->OfficialWalking();             duck->MakeFun();    cout << "---------- hooking --------" << endl;    typedef void(*DuckFunc)();    int * addr = (int*)duck;    DuckFunc f1 = (DuckFunc)(*((int*)(*addr)));    f1();    DuckFunc f2 = (DuckFunc)(*((int*)(*addr)+1));    f2();    typedef void(*ActorFunc)();    int * addr2 = (int*)(*(int*)((IActor*)duck));    ActorFunc f3 = (ActorFunc)(*(int*)(addr2));    f3();    return 0;}

記憶體布局為:


菱形繼承(略)

更多請參考

2、Go中的介面

Golang將interface作為一種類型,並且不依賴繼承,而是以一種類似於duck-typing的實現。所謂duck-typing,是一種動態類型風格:當一個obj走起來像鴨子、遊泳起來像鴨子、叫起來也像鴨子,那麼它就可以被稱為鴨子。

既然Go並沒有像C++那樣要求主動告訴編譯器需要繼承哪個父類,那麼是如何?動態類型的呢?(基於Go1.6,1.7及之後版本由於nameOff不方便gdb列印)

首先,interface由兩部分組成{tab, data},其中tab儲存了介面的中繼資料,這個很重要。

type iface struct {        tab  *itab        data unsafe.Pointer}

itab中比較重要的有interfacetype及fun[],其中interfacetype儲存了該介面需要實現哪些方法,fun[]則儲存動態類型是如何?這些方法的

type itab struct {        inter  *interfacetype        _type  *_type        link   *itab        bad    int32        unused int32        fun    [1]uintptr // variable sized}type interfacetype struct {        typ  _type        mhdr []imethod}type imethod struct {        name    *string        pkgpath *string        _type   *_type}

附:一篇經典論文中的圖解



research!rsc: Go Data Structures: Interfaces

e.g. 唐老鴨的go版本

package mainimport (    "fmt")type Duck interface {    GaGaSpeaking()()    OfficialWalking()()}type Actor interface {    MakeFun()()}type DonaldDuck struct {    height uint    name   string}func (dd *DonaldDuck) GaGaSpeaking()() {    fmt.Println("DonaldDuck gaga")}func (dd *DonaldDuck) OfficialWalking()() {    fmt.Println("DonaldDuck walk")}func (dd *DonaldDuck) MakeFun()() {    fmt.Println("DonaldDuck make fun")}func main() {    dd := &DonaldDuck{10, "tang lao ya" }    var duck Duck = dd    var actor Actor = dd    duck.GaGaSpeaking()    actor.MakeFun()    dd.OfficialWalking()}

我們用gdb調試一下
首先,看下結構類型與兩個介面的記憶體關係



可見,duck與actor的data指標都指向dd
然後是Duck介面的方法集:



以及其動態類型的具體實現:




可以看到,都指向了tanglaoya的具體實現

再看看Actor的方法集:




及其動態類型的具體實現



3、總結

C++在代碼編寫時就明確了是否實現某個介面,並將介面資訊附加在自己的記憶體中,但is-A的模式越來越限制模組間的解耦;Golang其寬鬆的介面充分降低了耦合的發生,但可能在代碼書寫無意中卻實現了某個介面.. 此外,其實現可能會比較繞,容易發生其他錯誤(比如經典的interface與nil的比較等等)

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.