OOC-用C實現物件導向

來源:互聯網
上載者:User
1、  概述C語言是一種面向過程的程式設計語言,而C++是在C語言基礎上衍生來了的物件導向的語言,實際上,很多C++實現的底層是用C語言實現的,如在Visual C++中的Interface其實就是struct,尋找Interface的定義,你可以發現有這樣的宏定義:#ifndef Interface#define Interface struct#endifC++在語言層級上添加了很多新機制(繼承,多態等),而在C語言中,我們也可以使用這樣的機制,前提是我們不得不自己實現。本文介紹了用C語言實現封裝,繼承和多態的方法。2、  基本知識在正式介紹C語言實現封裝,繼承和多態事前,先介紹一下C語言中的幾個概念和文法。(1)    結構體在C語言中,常把一個對象用結構體進行封裝,這樣便於對對象進行操作,比如:1strcut Point{ int x; int y; };結構體可以嵌套。因而可以把一個結構體當成另一個結構體的成員,如:1struct Circle { struct Point point_; int radius; };該結構體與以下定義完全一樣(包括記憶體布置都一樣):1struct Circle { int x; int y; int radius; };(2)    函數指標函數指標是指標的一種,它指向函數的首地址(函數的函數名即為函數的首地址),可以通過函數指標來調用函數。如函數:int func(int a[], int n);可以這樣聲明函數指標:int (*pFunc)(int a[], int n);這樣使用:pFunc = func;(*pFunc)(a, n);【或者PFunc(a, n)】可以用typedef定義一個函數指標類型,如:typdef int (*FUNC)(int a[], int n)可以這樣使用:int cal_a(FUNC fptr, int a[], int n){//實現體}(3)    extern與staticextern和static是C語言中的兩個修飾符,extern可用於修飾函數或者變數,表示該變數或者函數在其他檔案中進行了定義;static也可用於修飾函數或者變數,表示該函數或者變數只能在該檔案中使用。可利用它們對資料或者函數進行隱藏或者限制存取權限。3、  封裝在C語言中,可以用結構+函數指標來類比類的實現,而用這種結構定義的變數就是對象。封裝的主要含義是隱藏內部的行為和資訊,使用者只用看到對外提供的介面和公開的資訊。有兩種方法實現封裝:(1)    利用C語言文法。在標頭檔中聲明,在C檔案中真正定義它。這樣可以隱藏內部資訊,因為外部不知道對象所佔記憶體的大小,所以不能靜態建立該類的對象,只能調用類提供的建立函數才能建立。這種方法的缺陷是不支援繼承,因為子類中得不到任何關於父類的資訊。如://標頭檔:point.h #ifndef POINT_H #define POINT_H struct Point; typedef struct Point point; point * new_point(); //newer a point object void free_point(point *point_);// free the allocated space #endif //C檔案:point.c #include”point.h” strcut Point { int x; int y; }; point * new_point() { point * new_point_ = (point *) malloc(sizeof(point)); return new_point_; } void free_point(point *point_) { if(point_ == NULL) return; free(point_); }(2)    把私人資料資訊放在一個不透明的priv變數或者結構體中。只有類的實現代碼才知道priv或者結構體的真正定義。如:#ifndef POINT _H #define POINT_H typedef struct Point point; typedef struct pointPrivate pointPrivate; strcut Point { Struct pointPrivate *pp; }; int get_x(point *point_); int get_y(point *point_); point * new_point(); //newer a point object void free_point(point *point_);// free the allocated space #endif //C檔案:point.c #include”point.h” struct pointPrivate { int x; int y; } int get_x(point *point_) { return point_->pp->x; } int get_y(point *point_) { return point_->pp->y; } //others…..4、  繼承在C語言中,可以利用“結構在記憶體中的布局與結構的聲明具有一致的順序”這一事實實現繼承。比如我們要設計一個作圖工具,其中可能涉及到的對象有Point(點),Circle(圓),由於圓是由點組成的,所有可以看成Circle繼承自Point。另外,Point和Circle都需要空間申請,空間釋放等操作,所有他們有共同的基類Base。//記憶體管理類new.h #ifndef NEW_H #define NEW_H void * new (const void * class, ...); void delete (void * item); void draw (const void * self); #endif //記憶體管理類的C檔案:new.c #include “new.h” #include “base.h” void * new (const void * _base, ...) { const struct Base * base = _base; void * p = calloc(1, base->size); assert(p); * (const struct Base **) p = base; if (base ->ctor) { va_list ap; va_start(ap, _base); p = base ->ctor(p, &ap); va_end(ap); } return p; } void delete (void * self) { const struct Base ** cp = self; if (self && * cp && (* cp) —> dtor) self = (* cp) —>dtor(self); free(self); } void draw (const void * self) { const struct Base * const * cp = self; assert(self &&* cp && (* cp)->draw); (* cp) ->draw(self); } //基類:base.h #ifndef BASE_H #define BASE_H struct Base { size_t size; //類所佔空間 void * (* ctor) (void * self, va_list * app); //建構函式 void * (* dtor) (void * self); //解構函式 void (* draw) (const void * self); //作圖 }; #endif //Point標頭檔(對外提供的介面):point.h #ifndef   POINT_H #define  POINT_H extern const void * Point;                /* 使用方法:new (Point, x, y); */ #endif //Point內部標頭檔(外面看不到):point.r #ifndef POINT_R #define POINT_R struct Point { const void * base; //繼承,基類指標,放在第一個位置,const是防止修改 int x, y;        //座標 }; #endif //Point的C檔案:point.c #include “point.h” #include “new.h” #include “point.h” #include “point.r” static void * Point_ctor (void * _self, va_list * app) { struct Point * self = _self; self ->x = va_arg(* app, int); self ->y = va_arg(* app, int); return self; } static void Point_draw (const void * _self) { const struct Point * self = _self; printf(“draw (%d,%d)”, self -> x, self -> y); } static const struct Base _Point = { sizeof(struct Point), Point_ctor, 0, Point_draw }; const void * Point = & _Point; //測試程式:main.c #include “point.h” #include “new.h” int main (int argc, char ** argv) { void * p = new(Point, 1, 2); draw(p); delete(p); }同樣,Circle要繼承Point,則可以這樣:1struct Circle { const struct Point point; //放在第一位,可表繼承 int radius; };5、  多態可以是用C語言中的萬能指標void* 實現多態,接上面的例子:1//測試main.c void * p = new(Point, 1, 2); void * pp = new(Circle, 1, 2); draw(p); //draw函數實現了多態 draw(pp); delete(p); delete(pp);6、  總結C語言能夠類比實現物件導向語言具有的特性,包括:多態,繼承,封裝等,現在很多開源軟體都了用C語言實現了這幾個特性,包括大型開來源資料庫系統postgreSQL,可移植的C語言物件導向架構GObject,無線二進位運行環境BREW。採用C語言實現多態,繼承,封裝,能夠讓軟體有更好的可讀性,可擴充性。7、  參考資料(1)        《C語言中extern和static用法》:http://www.cnblogs.com/hishope/archive/2008/08/28/1278822.html(2)        《三、使用GObject——私人成員和靜態變數》:http://blog.csdn.net/wormsun/archive/2009/11/25/4874465.aspx(3)        《技巧:用 C 語言實現程式的多態性》:http://www.ibm.com/developerworks/cn/linux/l-cn-cpolym/index.html?ca=drs-(4)        書籍《Object-Oriented Programming With ANSI-C》8、  代碼下載http://code.google.com/p/cppdatastructurelib/source/browse/#svn%2Ftrunk%2Fooc%253Fstate%253Dclosed

聯繫我們

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