亚洲免费在线-亚洲免费在线播放-亚洲免费在线观看-亚洲免费在线观看视频-亚洲免费在线看-亚洲免费在线视频

C語言面向?qū)ο缶幊蹋ㄈ禾摵瘮?shù)與多態(tài)

系統(tǒng) 1785 0

在《 C++ 編程思想》一書中對虛函數(shù)的實現(xiàn)機制有詳細(xì)的描述,一般的編譯器通過虛函數(shù)表,在編譯時插入一段隱藏的代碼,保存類型信息和虛函數(shù)地址,而在調(diào)用時,這段隱藏的代碼可以找到和實際對象一致的虛函數(shù)實現(xiàn)。

我們在這里提供一個 C 中的實現(xiàn),模仿 VTABLE 這種機制,但一切都需要我們自己在代碼中裝配。

之前在網(wǎng)上看到一篇描述 C 語言實現(xiàn)虛函數(shù)和多態(tài)的文章,談到在基類中保存派生類的指針、在派生類中保存基類的指針來實現(xiàn)相互調(diào)用,保障基類、派生類在使用虛函數(shù)時的行為和 C++ 類似。我覺得這種方法有很大的局限性,不說繼承層次的問題,單單是在基類中保存派生類指針這一做法,就已經(jīng)違反了虛函數(shù)和多態(tài)的本意——多態(tài)就是要通過基類接口來使用派生類,如果基類還需要知道派生類的信息……。

我的基本思路是:

  • 在“基類”中顯式聲明一個 void** 成員,作為數(shù)組保存基類定義的所有函數(shù)指針,同時聲明一個 int 類型的成員,指明 void* 數(shù)組的長度。
  • “基類”定義的每個函數(shù)指針在數(shù)組中的位置、順序是固定的,這是約定,必須的
  • 每個“派生類”都必須填充基類的函數(shù)指針數(shù)組(可能要動態(tài)增長),沒有重寫虛函數(shù)時,對應(yīng)位置置 0
  • “基類”的函數(shù)實現(xiàn)中,遍歷函數(shù)指針數(shù)組,找到繼承層次中的最后一個非 0 的函數(shù)指針,就是實際應(yīng)該調(diào)用的和對象相對應(yīng)的函數(shù)實現(xiàn)

好了,先來看一點代碼:

    struct base {
    void ** vtable;
    int vt_size;
    
    void (*func_1)(struct base *b);
    int (*func_2)(struct base *b, int x);
};

struct derived {
    struct base b;
    int i;
};

struct derived_2{
    struct derived d;
    char *name;
};
  
上面的代碼是我們接下來要討論的,先說一點,在 C 中,用結(jié)構(gòu)體內(nèi)的函數(shù)指針和 C++ 的成員函數(shù)對應(yīng), C 的這種方式,所有函數(shù)都天生是虛函數(shù)(指針可以隨時修改哦)。

注意,derived 和 derived_2 并沒有定義 func_1 和 func_2 。在 C 的虛函數(shù)實現(xiàn)中,如果派生類要重寫虛函數(shù),不需要在派生類中顯式聲明。要做的是,在實現(xiàn)文件中實現(xiàn)你要重寫的函數(shù),在構(gòu)造函數(shù)中把重寫的函數(shù)填入虛函數(shù)表。

我們面臨一個問題,派生類不知道基類的函數(shù)實現(xiàn)在什么地方(從高內(nèi)聚、低耦合的原則來看),在構(gòu)造派生類實例時,如何初始化虛函數(shù)表?在 C++ 中編譯器會自動調(diào)用繼承層次上所有父(祖先)類的構(gòu)造函數(shù),也可以顯式在派生類的構(gòu)造函數(shù)的初始化列表中調(diào)用基類的構(gòu)造函數(shù)。怎么辦?

我們提供一個不那么優(yōu)雅的解決辦法:

每個類在實現(xiàn)時,都提供兩個函數(shù),一個構(gòu)造函數(shù),一個初始化函數(shù),前者用戶生成一個類,后者用于繼承層次緊接自己的類來調(diào)用以便正確初始化虛函數(shù)表。依據(jù)這樣的原則,一個派生類,只需要調(diào)用直接基類的初始化函數(shù)即可,每個派生類都保證這一點,一切都可以進行下去。

下面是要實現(xiàn)的兩個函數(shù):

    struct derived *new_derived();
void initialize_derived(struct derived *d);
  
new 開頭的函數(shù)作為構(gòu)造函數(shù), initialize 開頭的函數(shù)作為 初始化函數(shù)。我們看一下 new_derived 這個構(gòu)造函數(shù)的實現(xiàn)框架:

    struct derived *new_derived()
{
    struct derived * d = malloc(sizeof(struct derived));
    initialize_base((struct base*)d);
    initialize_derived(d);/* setup or modify VTABLE */
    return d;
}
  
如果是 derived_2 的構(gòu)造函數(shù) new_derived_2,那么只需要調(diào)用 initialize_derived 即可。

說完了構(gòu)造函數(shù),對應(yīng)的要說析構(gòu)函數(shù),而且析構(gòu)函數(shù)要是虛函數(shù)。在刪除一個對象時,需要從派生類的析構(gòu)函數(shù)依次調(diào)用到繼承層次最頂層的基類的析構(gòu)函數(shù)。這點在 C 中也是可以保障的。做法是:給基類顯式聲明一個析構(gòu)函數(shù),基類的實現(xiàn)中查找虛函數(shù)表,從后往前調(diào)用即可。函數(shù)聲明如下:

    struct base {
    void ** vtable;
    int vt_size;
    
    void (*func_1)(struct base *b);
    int (*func_2)(struct base *b, int x);
    void (*deletor)(struct base *b);
};
  

說完構(gòu)造、析構(gòu),該說這里的虛函數(shù)表到底是怎么回事了。我們先畫個圖,還是以剛才的 base 、 derived 、derived_2 為例來說明,一看圖就明白了:

C語言面向?qū)ο缶幊蹋ㄈ禾摵瘮?shù)與多態(tài)


我們假定 derived 類實現(xiàn)了三個虛函數(shù), derived_2 類實現(xiàn)了兩個,func_2 沒有實現(xiàn),上圖就是 derived_2 的實例所擁有的最終的虛函數(shù)表,表的長度( vt_size )是 9。如果是 derived 的實例,就沒有表中的最后三項,表的長度( vt_size )是 6 。

必須限制的是:基類必須實現(xiàn)所有的虛函數(shù),只有這樣,這套實現(xiàn)機制才可以運轉(zhuǎn)下去。因為一切的發(fā)生是從基類的實現(xiàn)函數(shù)進入,通過遍歷虛函數(shù)表來找到派生類的實現(xiàn)函數(shù)的。

當(dāng)我們通過 base 類型的指針(實際指向 derived_2 的實例)來訪問 func_1 時,基類實現(xiàn)的 func_1 會找到 VTABLE 中的 derived_2_func_1 進行調(diào)用。

好啦,到現(xiàn)在為止,基本說明白了實現(xiàn)原理,至于 初始化函數(shù)如何裝配虛函數(shù)表、基類的虛函數(shù)實現(xiàn),可以根據(jù)上面的思路寫出代碼來。按照我的這種方法實現(xiàn)的虛函數(shù),通過基類指針訪問,行為基本和 C++ 一致。

回顧一下:

C語言面向?qū)ο缶幊蹋ㄈ禾摵瘮?shù)與多態(tài)


更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號聯(lián)系: 360901061

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。

【本文對您有幫助就好】

您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描上面二維碼支持博主2元、5元、10元、自定義金額等您想捐的金額吧,站長會非常 感謝您的哦!!!

發(fā)表我的評論
最新評論 總共0條評論
主站蜘蛛池模板: 亚洲综合爱爱久久网 | 久久爱综合久久爱com | 日本高清在线精品一区二区三区 | 特级毛片免费播放 | 久久久久国产精品免费 | 日本高清视频www夜色资源网 | 国产精品久久久久久久久久日本 | 国产精品二区高清在线 | 玖玖国产在线 | 羞羞视频免费观看网站 | 成人午夜在线观看 | 国产精品美女一区二区三区 | 九九九国产 | 日本人xx视频免费视频 | 日韩在线a视频免费播放 | 久久羞羞 | 欧美国产日韩在线 | 国产在线一区二区三区在线 | 日日碰日日摸日日澡视频播放 | 亚洲国产人久久久成人精品网站 | 国产香蕉75在线播放 | 97精品一区二区三区在线不卡 | 天天干天天插天天操 | 久草在线视频资源 | 久久久久一区二区三区 | 免费在线观看h片 | 综合网视频 | 久久是免费只精品热在线 | 中文字幕免费在线看线人动作大片 | 精品1区2区3区 | 国产综合色在线视频区色吧图片 | 久久久久久亚洲精品影院 | 国产精品成人69xxx免费视频 | 2021久久精品永久免费 | 欧美性猛交xxxx免费看久久 | 丹武至尊在线观看动漫 | 久久毛片网站 | 国产玖玖视频 | 日本一级α一片免费视频 | 天天操天天干天天玩 | 国产女主播在线视频 |