欧美三区_成人在线免费观看视频_欧美极品少妇xxxxⅹ免费视频_a级毛片免费播放_鲁一鲁中文字幕久久_亚洲一级特黄

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

系統(tǒng) 1612 0

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

我們?cè)谶@里提供一個(gè) C 中的實(shí)現(xiàn),模仿 VTABLE 這種機(jī)制,但一切都需要我們自己在代碼中裝配。

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

我的基本思路是:

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

好了,先來(lái)看一點(diǎ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;
};
  
上面的代碼是我們接下來(lái)要討論的,先說(shuō)一點(diǎn),在 C 中,用結(jié)構(gòu)體內(nèi)的函數(shù)指針和 C++ 的成員函數(shù)對(duì)應(yīng), C 的這種方式,所有函數(shù)都天生是虛函數(shù)(指針可以隨時(shí)修改哦)。

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

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

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

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

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

    struct derived *new_derived();
void initialize_derived(struct derived *d);
  
new 開(kāi)頭的函數(shù)作為構(gòu)造函數(shù), initialize 開(kāi)頭的函數(shù)作為 初始化函數(shù)。我們看一下 new_derived 這個(gè)構(gòu)造函數(shù)的實(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 即可。

說(shuō)完了構(gòu)造函數(shù),對(duì)應(yīng)的要說(shuō)析構(gòu)函數(shù),而且析構(gòu)函數(shù)要是虛函數(shù)。在刪除一個(gè)對(duì)象時(shí),需要從派生類的析構(gòu)函數(shù)依次調(diào)用到繼承層次最頂層的基類的析構(gòu)函數(shù)。這點(diǎn)在 C 中也是可以保障的。做法是:給基類顯式聲明一個(gè)析構(gòu)函數(shù),基類的實(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);
};
  

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

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


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

必須限制的是:基類必須實(shí)現(xiàn)所有的虛函數(shù),只有這樣,這套實(shí)現(xiàn)機(jī)制才可以運(yùn)轉(zhuǎn)下去。因?yàn)橐磺械陌l(fā)生是從基類的實(shí)現(xiàn)函數(shù)進(jìn)入,通過(guò)遍歷虛函數(shù)表來(lái)找到派生類的實(shí)現(xiàn)函數(shù)的。

當(dāng)我們通過(guò) base 類型的指針(實(shí)際指向 derived_2 的實(shí)例)來(lái)訪問(wèn) func_1 時(shí),基類實(shí)現(xiàn)的 func_1 會(huì)找到 VTABLE 中的 derived_2_func_1 進(jìn)行調(diào)用。

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

回顧一下:

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


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

微信掃碼或搜索:z360901061

微信掃一掃加我為好友

QQ號(hào)聯(lián)系: 360901061

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

【本文對(duì)您有幫助就好】

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

發(fā)表我的評(píng)論
最新評(píng)論 總共0條評(píng)論
主站蜘蛛池模板: 污污网站国产精品白丝袜 | 国产一区日韩精品 | 2021国产成人午夜精品 | 欧美视频在线一区 | 欧美日本一区 | 激情小说图 | 国产亚洲99影院 | 男人天堂网av | 日日操夜夜操天天操 | 久久综合九色综合网站 | 久久精品一区 | 国产精品毛片在线 | 日韩欧美小视频 | 日韩电影在线看 | 91.成人天堂一区 | 日韩一区二区福利视频 | 精品一区二区久久久久久久网站 | 国内精品久久毛片一区二区 | 日韩国产欧美视频 | 成人资源在线观看 | 成人免费网站视频 | 国产精品男人的天堂 | 粉色视频高清大全免费观看1 | 国产精品美女久久久久aⅴ国产馆 | jizzjizz日本护士视频 | 中文字幕 欧美 日韩 | 久久精品无码一区二区日韩av | 精品国产不卡一区二区三区 | 国产成人免费视频网站高清观看视频 | 爱爱视频在线观看 | 92午夜影院 | 国产一级影视 | 久久精品天堂 | 天天摸天天碰成人免费视频 | 澳门一级毛片免费播放 | 亚洲浮力影院 | www.久草 | 欧洲精品久久久 | 污网站免费 | 欧美激情专区 | 男女无遮挡高清性视频直播 |