日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

C语言面向对象编程(四):面向接口编程

發布時間:2025/3/12 编程问答 24 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C语言面向对象编程(四):面向接口编程 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
Java 中有 interface 關鍵字,C++ 中有抽象類或純虛類可以與 interface 比擬,C 語言中也可以實現類似的特性。

? ? 在面試 Java 程序員時我經常問的一個問題是:接口和抽象類有什么區別。

? ? 很多編程書籍也經常說要面向接口編程,我的理解是,接口強制派生類必須實現基類(接口)定義的契約,而抽象類則允許實現繼承從而導致派生類可以不實現(重寫)基類(接口)定義的契約。通常這不是問題,但在有一些特定的情況,看起來不那么合適。

? ? 比如定義一個 Shape 基類,其中定義一個 draw() 方法,給一個什么都不做的默認實現(通常是空函數體),這實際沒有任何意義。

? ? 再比如基類改變某個方法的實現,而派生類采用實現繼承并沒有重寫這個方法,此時可能會導致一些奇怪的問題。以鳥為例,基類為 Bird ,我們可能會定義一個 fly() 方法,一個 walk() 方法,因為有的人認為鳥既可以走又可以飛。開始時我們在 walk() 的實現里作了假定,認為雙腳交叉前進才是 walk ,可是后來發現有些鳥是雙腳一齊蹦的,不會交叉前進。這個時候怎么辦?基類 Bird 的 walk() 方法是否要修改、如何修改?

? ? 在 C++ 中,沒有接口關鍵字 interface ,同時為了代碼復用,經常采用實現繼承。在 C 語言中,我們前面幾篇文章討論了封裝、隱藏、繼承、虛函數、多態等概念,雖然都可以實現,但使用起來總不如自帶這些特性的語言(如 C++ 、Java )等得心應手。一旦你采用我們前面描述的方法來進行面向對象編程,就會發現,在 C 語言中正確的維護類層次是一件非常繁瑣、容易出錯的事情,而且要比面向對象的語言多寫很多代碼(這很容易理解,面向對象語言自帶輪子,而 C 要自己造輪子,每實現一個類都要造一遍)。但有一點,當我們使用 C 語言作面向對象編程時,比 C++ 有明顯的優勢,那就是接口。

? ? 接口強制派生類實現,這點在 C 中很容易做到。而且我們在編程中,實際上多數時候也不需要那么多的繼承層次,一個接口類作為基類,一個實現類繼承接口類,這基本就夠了。在 C 語言中采用這種方式,可以不考慮析構函數、超過 3 層繼承的上下類型轉換、虛函數調用回溯、虛函數表裝配等等問題,我們所要做的,就是實現基類接口,通過基類指針,就只能操作繼承層次中最底層的那個類的對象;而基類接口,天生就是不能實例化的(其實是實例化了沒辦法使用,因為結構體的函數指針沒人給它賦值)。

? ? 一個示例如下:

[cpp] view plaincopy print?
  • struct?base_interface?{??
  • ????void?(*func1)(struct?base_interface*?b);??
  • ????void?(*func2)(struct?base_interface*?b);??
  • ????int?(*func_3)(struct?base_interface*?b,?char?*?arg);??
  • };??
  • ??
  • struct?derived?{??
  • ????struct?base_interface?bi;??
  • ????int?x;??
  • ????char?ch;??
  • ????char?*name;??
  • };??
  • struct base_interface {void (*func1)(struct base_interface* b);void (*func2)(struct base_interface* b);int (*func_3)(struct base_interface* b, char * arg); };struct derived {struct base_interface bi;int x;char ch;char *name; };
    ? ? 上面是頭文件,derived 結構體通過包含 base_interface 類型的成員 bi 來達到繼承的效果;而 base_interface 無法實例化,我們沒有提供相應的構造函數,也沒有提供與 func_1 , func_2 等函數指針對應的實現,即便有人 malloc 了一個 base_interface ,也無法使用。

    ? ? derived 類可以提供一個構造函數 new_derived ,同時在實現文件中提供 func_1 , func_2 ,func_3 的實現并將函數地址賦值給 bi 的成員,從而完成 derived 類的裝配,實現 base_interface 定義的契約。

    ? ? 示例實現如下:

    [cpp] view plaincopy print?
  • static?void?_derived_func_1(struct?base_interface?*bi)??
  • {??
  • ????struct?derived?*?d?=?(struct?derived*)bi;??
  • ????d->x?*=?2;??
  • ????printf("d->name?=?%s\n",?d->name);??
  • }??
  • ??
  • /*?_derived_func_2?impl?*/??
  • /*?_derived_func_3?impl?*/??
  • ??
  • struct?derived?*new_derived()??
  • {??
  • ????struct?derived?*d?=?malloc(sizeof(struct?derived));??
  • ????d->bi.func_1?=?_derived_func_1;??
  • ????d->bi.func_2?=?_derived_func_2;??
  • ????d->bi.func_3?=?_derived_func_3;??
  • ????d->x?=?0;??
  • ????d->ch?=?'a';??
  • ????d->name?=?NULL;??
  • ??
  • ????return?d;??
  • }??
  • static void _derived_func_1(struct base_interface *bi) {struct derived * d = (struct derived*)bi;d->x *= 2;printf("d->name = %s\n", d->name); }/* _derived_func_2 impl */ /* _derived_func_3 impl */struct derived *new_derived() {struct derived *d = malloc(sizeof(struct derived));d->bi.func_1 = _derived_func_1;d->bi.func_2 = _derived_func_2;d->bi.func_3 = _derived_func_3;d->x = 0;d->ch = 'a';d->name = NULL;return d; }
    ? ? 我們可以這么使用 base_interface 接口:

    [cpp] view plaincopy print?
  • void?do_something(struct?base_interface?*bi)??
  • {??
  • ????bi->func_1(bi);??
  • }??
  • ??
  • int?main(int?argc,?char?**argv)??
  • {??
  • ????struct?derived?*?d?=?new_derived();??
  • ????do_something((struct?base_interface*)d);??
  • ??
  • ????return?0;??
  • }??
  • void do_something(struct base_interface *bi) {bi->func_1(bi); }int main(int argc, char **argv) {struct derived * d = new_derived();do_something((struct base_interface*)d);return 0; }
    ? ? 上面的代碼中 do_something 函數完全按照接口編程,而 bi 可以實際指向任意一個實現了 base_interface 接口的類的實例,在一定程序上達到多態的效果,花費的代價相當小,卻可以讓我們的程序提高可擴展性,降低耦合。

    ? ? 這種簡單的方法也是我在自己的項目中使用的方法,效果不錯。

    ? ? 好啦,C 語言面向對象編程系列的基礎性介紹就告一段落,下面是前幾篇的鏈接,有興趣的可以回頭看看:

    • C語言面向對象編程(一):封裝與繼承
    • C語言面向對象編程(二):繼承詳解
    • C語言面向對象編程(三):虛函數與多態

    ? ? 接下來我會提供幾個實作的例子,包括基本的數據結構,如單鏈表、樹,還有一個 http server 的例子。

    總結

    以上是生活随笔為你收集整理的C语言面向对象编程(四):面向接口编程的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。