純C語言實現簡單封裝繼承機制

來源:互聯網
上載者:User

標籤:tty   程式猿   app   優點   oat   char   http   樣書   define   

0 繼承是OO設計的基礎

繼承是OO設計中的基本部分,也是實現多態的基礎,C++,C#,Objective-C。Java。PHP。JavaScript等為OO而設計的語言,其語言本身對實現繼承提供了直接支援。而遵循C/Unix設計哲學的語言,從不限定編程風格。並且提供了實現OO的基本支援。以下我們就來看看怎樣用C語言實現繼承。

1 記憶體布局層面上繼承的含義

現在差點兒全部程式猿都知道繼承的抽象含義,對於被用爛了的貓狗繼承動物的範例也耳熟能詳。在此,我們拋開抽象世界,深入到繼承的詳細實現上。當然不同的語言對繼承的實現機制並不全然同樣,可是瞭解當中一種典型的實現細節對於理解繼承是很有優點的。這裡我們以C++為例進行說明。

class B{    int x;    int y;    int z;};class C : B{    float f;    char s[10];};

上述代碼錶示子類C繼承了父類B。以下是類C的一個執行個體(對象)的記憶體布局。


C對象有兩部分組成,紅色地區是繼承自B的部分,藍色地區是自身特有的。這樣一來,紅色部分全然能夠當成是一個B類對象。

2 利用結構體實現繼承的兩種方法2.1 父類對象作為子類的成員

理解了繼承的記憶體布局原理之後,用C來實現繼承就很easy了。最easy想到的方法例如以下:

struct B{    int x;    int y;    int z;};struct C{    struct B objB;    float f;    char s[10];};

上述代碼通過在C中包括一個B類型的成員來實現繼承,此方法很直接。但使用起來有一些不太方便。

    struct C objC;    objC.objB.x = 10;    ((struct B*)&objC)->x = 10;

要想訪問父類的成員x,有兩種方法。一種是objC.objB.x;還有一種是((struct B*)&objC)->x = 10。

這兩種方式都看起來不夠直接。而在子類方法中訪問父類成員是很頻繁的。

void c_member_method(struct C* pObjC){    pObjC->objB.x = 20; /* 訪問父類成員 */    pObjC->f = 0.23f; /* 訪問自身成員 */}

第一種方法,感覺更像是OB風格。而不是OO。


另外一種方法,必須進行強制類型轉換,感覺文法上不夠美觀。

2.2 子類包括全部的父類成員
struct C{    int x;    int y;    int z;    float f;    char s[10];};

把全部的父類成員原樣作為子類的成員。這樣子類對象訪問繼承來的成員就很直接了。

void c_member_method(struct C* pObjC){    pObjC->x = 20; /* 訪問父類成員 */    pObjC->f = 0.23f; /* 訪問自身成員 */}void main(){    struct C objC;    objC.x = 10;}

看起來很好,實際上在project上會存在一個很大的問題:難以維護。比如,每當建立一個子類。必須原樣書寫全部的父類成員,當父類定義變動時,子類須要做出同樣的改動。一旦父類稍具規模,維護這樣的繼承關係將是一場噩夢。

那麼怎樣解決的?
方法是現成的,那就是利用C語言的預先處理宏定義#define. 例如以下所看到的:

#define B_STRUCT \    int x;     int y;     int zstruct B{    B_STRUCT;};struct C{    B_STRUCT;    float f;    char s[10];};

當繼承層級更深時。比如 C繼承B,D繼承C,能夠照搬此方法。

#define B_STRUCT \    int x;     int y;     int zstruct B{    B_STRUCT;};#define C_STRUCT \    B_STRUCT;     float f;     char s[10]struct C{    C_STRUCT;};#define D_STRUCT \    C_STRUCT;     double dstruct D{    D_STRUCT;};

通過宏定義。能夠很easy實現和維護這樣的繼承關係。

3 方法(成員函數)的封裝與繼承

C語言中沒有成員函數的概念,語言本身也不支援。

使用C語言實現真正的成員函數差點兒是不可能的,除非嵌入組合語言。與其使用組合語言,還不如直接使用C++呢。

所以,我們不追求形式上的成員函數,僅僅實現意義上的成員函數–(對給定類型對象進行操作)的函數,並使用帶結構名首碼的函數名加以命名之。

我們還是以上面的範例進行說明。

typedef struct B B;static void b_member_function(B* pobjB) /* 類B的成員函數 */{}typedef struct C C;static void c_member_function(C* pobjC) /* 類C的成員函數 */{}

對成員函數的調用,有兩種情形:(1)外部代碼調用成員函數;(2)子類成員函數中調用父類的成員函數;

static void c_member_function(C* pobjC){    b_member_function((B*)pobjC); /* 子類成員函數內部調用父類成員函數 */}void main(){    C* pObjC = malloc(sizeof(C));    b_member_function((B*)pObjC);  /* 外部代碼調用成員函數 */    free(pObjC);}

這兩種情況都須要對實參進行強制類型轉換為父類型。C編譯器對類型繼承關係一無所知,無法從文法上對繼承進行自己主動支援,所以僅僅能手動強制類型轉換了。

有些人喜歡更進一步類比成員函數。把全部成員函數的地址作為指標類型的成員變數儲存到結構體內部。

例如以下:

#define B_STRUCT \    int x;     int y;     int z;     void (*pb_member_function1)(B*);     void (*pb_member_function2)(B*, int arg)struct B{    B_STRUCT;   };/* 初始化B對象的同一時候初始化 */B* b = malloc(sizeof(B));b->pb_member_function1 = b_member_function1;b->pb_member_function2 = b_member_function2;/* 調用 */b->b_member_function1(b);

這樣形式上更加接近“成員函數”。但同一時候也帶來了額外的記憶體開銷和代碼量。

為了減小記憶體消耗,有人提出不再在對象中全然存放全部成員函數指標,而是僅僅存放一個指向成員函數地址清單的指標。畢竟,同一類型的全部執行個體(對象)共用同樣的一群組成員函數。

/* B類型的成員方法表 */const struct B_MethodTable{    void (*pb_member_function1)(B*);     void (*pb_member_function2)(B*, int arg);}b_method_table{    b_member_function1,    b_member_function2,};#define B_STRUCT \    int x;     int y;     int z;     struct B_MethodTable * pMethodTable;struct B{    B_STRUCT;   };/* 初始化B對象的同一時候初始化 */B* b = malloc(sizeof(B));b->pMethodTable = &b_method_table;/* 調用 */b->pMethodTable->pb_member_function1(b);

這樣在一定程度上減小了記憶體佔用量和代碼量,可是隊成員函數的調用寫法卻變得很繁瑣不自然。

4 做到何種程度?

使用C語言做OO開發時,要掌握好一個度。不要過分追求對OO語言C++的類比,全然類比C++的話,還不如乾脆直接使用C++。

  • 有些語言特性無法類比,如C++中private,protected等訪問限定符。成員函數的this指標。更應該注重意義上的類比。通過一些命名規則和約定來達到OO。

  • 永遠不要違背C語言的設計哲學:程式猿控制一切,直接簡明。

這個度的把握須要依據詳細的項目規模和需求。是實踐中摸索出來的。無法給出理論上的最優值。

純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.