實用OOPC

c語言是面向過程而進行程序設計的語言。而在程序設計時,面向對象的方式進行設計可以簡化很多事情。因此一直在尋找一些可以使用面向對象的方式使用C語言進行開發。

前期寫過一些面向對象的設計方式,

點半:OOPC-C面向對象zhuanlan.zhihu.com圖標

但存在的一個問題就是使用麻煩,並且也存在內存泄漏的問題,所以效果一直不是很好。

針對這些問題對C語言面向對象重新進行了設計:

/************************************************* * Copyright ? person * File name : oopc.h * Author : pxf * Version : v1.0 * Created on : 2018/2/8 * Description : 本文件內定義的宏用於生成C代碼的面向對象。 * 1.目前面向對象的介面、抽象類、實類之間的基本關係操作都已實現; * 2.INF/AC/CL分別用於聲明介面、抽象類、實類,其使用盡量放在.h文件中; * 3.ACC/ACD/CC/CD分別用於定義抽象類、實類構造及析構函數,其使用必須在.c文件中; * 4.CACC/CACD/CCC/CCD分別用於實類實例化時構造函數中調用被繼承類(抽象類、實類) * 的構造及析構函數來實例化被繼承類,其使用必須在.c文件中; * 5.IMPL/EXT分別用於繼承介面及抽象類、實類; * 6.SUB/SUBC分別用於在介面及抽象類、實類中的函數內獲得繼承子類指針cthis; * 7.FS配置實類中的參數,不限於函數,實類參數配置儘可能通過FS配置,而不是init進行傳參配置; * 8.CN/CNNP/CF實例化或釋放實類對象; * 9.由於CN/CNNP/CF/CCC操作後沒有返回值,可以通過OPRS查看前一步操作結果; * 10.實類聲明中必須附帶兩個參數self,init; * self - 指向自身的指針,也可以指示當前實例是否可用,self指向自身時實類可用,self為OOPC_NULL時實類已釋放; * init - 配置實類中參數,init函數有個要求在函數參數聲明中指向自身實類指針必須聲明為cthis; * 為了初始化更加統一,介面及抽象類需要通過init傳遞進行配置, * 實類自身函數需要通過FS進行設置,除非特別需求可通過init配置; * 實類如有繼承,則被繼承類所有相關函數都得通過init進行配置; * Others : 無 * History : 180208 pxf 初次建立 * 180302 pxf 1.為適應不同編譯器對實類進行的實例化,增加特殊的無參宏CNNP * 2.增加宏版本定義,當前版本為v1.01 ************************************************/#ifndef OOPC_H_#define OOPC_H_// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// 版本定義---------------------------------------------------------------------#define OOPC_MACRO_VERSION 0xC01D01 // C代表v,D代表.,當前版本v1.01// 通用宏定義-------------------------------------------------------------------#define OOPC_FALSE 0 // (操作)失敗#define OOPC_TRUE 1 // (操作)成功#define OOPC_NULL ((void *)0) // 空指針// 配置選項---------------------------------------------------------------------#define OOPC_USE_USER_DEFINED_OFFSETOF OOPC_TRUE // 是否使用用戶定義的OOPC_OFFSETOF,OOPC_FALSE時使用C標準庫中的offsetof#define OOPC_USE_STATIC_INLINE_OPTIMIZE OOPC_TRUE // 是否使用static inline對構造及析構函數代碼調用進行優化#define OOPC_RETURN_DATATYPE int // 定義析構函數等返回數據類型// 配置選擇---------------------------------------------------------------------#if (OOPC_USE_USER_DEFINED_OFFSETOF == OOPC_TRUE) // 配置OOPC_OFFSETOF // 有些環境可能不支持,不過,這種情形極少出現 #define OOPC_OFFSETOF(type, member) (size_t)&(((type *)0)->member)#else #include <stddef.h> // size_t offsetof(structName, memberName); // 第一個參數是結構體的名字,第二個參數是結構體成員的名字。 // 該宏返回結構體structName中成員memberName的偏移量。偏移量是size_t類型的。 #define OOPC_OFFSETOF offsetof#endif#if (OOPC_USE_STATIC_INLINE_OPTIMIZE == OOPC_TRUE) // 配置OOPC_STATIC_INLINE #define OOPC_STATIC_INLINE static inline#else #define OOPC_STATIC_INLINE#endif// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// 介面及類的繼承關係-----------------------------------------------------------#define IMPL(type) type type // 介面、抽象類進行繼承Implement#define EXT(type) h##type type// 實類進行繼承Extends// 類的繼承建議一級繼承,不建議多級繼承------------------------------------------// 實類繼承子類(繼承類)指針 subordinate,self pointer#define SUBC(selfpointer, hselftype, childtype) h##childtype cthis = ((h##childtype)((char *)(*selfpointer) - OOPC_OFFSETOF(childtype, hselftype)))// 抽象類或介面繼承子類(繼承類)指針#define SUB(selfpointer, selftype, childtype) h##childtype cthis = ((h##childtype)((char *)selfpointer - OOPC_OFFSETOF(childtype, selftype)))// 在構造函數中對類的參數(不止是函數,其他變數也行)進行配置 function,setting-----// 在一個類中如果是通用的配置,那麼盡量使用FS放在構造函數中,而不是通過init配置一些可變的參數#define FS(ClassFunction, SourceFunction) cthis->ClassFunction = SourceFunction// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// 介面及抽象類、實類的聲明------------------------------------------------------// Interface介面進行聲明#define INF(type) typedef struct type *h##type, type; struct type// Abstract Class抽象類進行聲明#define AC(type) typedef struct type *h##type, type; struct type// Class實類進行聲明// 實類聲明中必須要以下self,init兩個有參數定義// self指向自身,最好放在參數的第一個,h##type self// init有參數要求並且返回自身類型指針,h##type (*init)(classptr cthis,...)// init參數中類指針必須聲明為cthis,而其他所有函數參數中都不可以有cthis的參數出現// 介面函數、抽象類函數、以及類自身不在同一文件內的函數可以通過init函數傳參進行初始化// 類其餘在同一文件內函數最好通過FS直接進行配置// 示例:// CL(Aaa)// {// hAaa self;// hAaa (*init)(hAaa cthis, ...);// ...// }#define CL(type) typedef struct type **hh##type, *h##type, type; h##type type##_new(void *self); OOPC_RETURN_DATATYPE type##_delete(h##type t); struct type// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// 抽象類、實類構造函數及析構函數定義--------------------------------------------// 定義抽象類構造函數abstract class constructor,需要返回值cthis/OOPC_NULL#define ACC(type) OOPC_STATIC_INLINE h##type type##_ctor(h##type cthis); OOPC_STATIC_INLINE h##type type##_ctor(h##type cthis)// 定義抽象類析構函數abstract class destructor,需要返回值OOPC_TRUE/OOPC_FALSE#define ACD(type) OOPC_STATIC_INLINE OOPC_RETURN_DATATYPE type##_dtor(h##type cthis); OOPC_STATIC_INLINE OOPC_RETURN_DATATYPE type##_dtor(h##type cthis)// 定義實類構造函數class constructor,需要返回值cthis/OOPC_NULL#define CC(type) OOPC_STATIC_INLINE h##type type##_ctor(h##type cthis); h##type type##_new(void *self){ h##type cthis = (h##type)self; h##type Rtv = OOPC_NULL; if (OOPC_NULL != cthis){ cthis->self = cthis; if (OOPC_NULL == type##_ctor(cthis)){ cthis->self = OOPC_NULL; Rtv = OOPC_NULL; } else { Rtv = cthis; } } else { Rtv = OOPC_NULL; } return Rtv; /* 當前不去獲取內存,只對傳輸進來的內存進行配置 */ } OOPC_STATIC_INLINE h##type type##_ctor(h##type cthis)// 定義實類析構函數class destructor,需要返回值OOPC_TRUE/OOPC_FALSE#define CD(type) OOPC_STATIC_INLINE OOPC_RETURN_DATATYPE type##_dtor(h##type cthis); OOPC_RETURN_DATATYPE type##_delete(h##type cthis){ OOPC_RETURN_DATATYPE Rtv = OOPC_FALSE; if (OOPC_NULL != cthis){ cthis->self = OOPC_NULL; if (OOPC_TRUE == type##_dtor(cthis)){ Rtv = OOPC_TRUE; } else { Rtv = OOPC_FALSE; } } else { Rtv = OOPC_FALSE; } return Rtv; /* 當前不去釋放內存,只對傳輸進來的內存進行配置 */ } OOPC_STATIC_INLINE OOPC_RETURN_DATATYPE type##_dtor(h##type cthis)// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// 類實例化時,抽象類、實類父類構造及析構函數的調用-------------------------------// 調用抽象類構造函數call abstract class constructor,有返回值cthis/OOPC_NULL#define CACC(father) father##_ctor(&(cthis->father))// 調用抽象類析構函數call abstract class destructor,有返回值OOPC_TRUE/OOPC_FALSE#define CACD(father) father##_dtor(&(cthis->father))// 調用類構造函數call class constructor,有返回值cthis/OOPC_NULL#define CCC(father, fatherptr, ...) do { cthis->father = father##_new((void *)(fatherptr)); if (OOPC_NULL != cthis->father){ if (OOPC_NULL == cthis->father->init(cthis->father, __VA_ARGS__)){ if (OOPC_TRUE == father##_delete(cthis->father)){ ; } else { ; } cthis->father = OOPC_NULL; } else { ; } } else { ; } } while (0)// 調用類析構函數call class destructor,有返回值OOPC_TRUE/OOPC_FALSE#define CCD(father) father##_delete((cthis->father))// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>// 實類實例化及釋放Class New/Free,參數個數任意----------------------------------// CF多個參數是類實例化通過init函數進行配置的參數傳遞決定的#define CN(type, classptr, ...) do { if (OOPC_NULL != type##_new((void *)(classptr))){ if (OOPC_NULL == (classptr)->init((classptr), __VA_ARGS__)){ if (OOPC_TRUE == type##_delete(classptr)){ ; } else { ; } } else { ; } } else { ; } } while (0)// Class New Without(No) Param無參類實例化#define CNNP(type, classptr) do { if (OOPC_NULL != type##_new((void *)(classptr))){ if (OOPC_NULL == (classptr)->init(classptr)){ if (OOPC_TRUE == type##_delete(classptr)){ ; } else { ; } } else { ; } } else { ; } } while (0)// ClassFree對類資源進行釋放#define CF(type, classptr) do { if (OOPC_NULL != (classptr)){ if (OOPC_TRUE == type##_delete(classptr)){ ; } else { ; } } else { ; } } while (0)// 由於CN/CNNP/CF/CCC調用後沒有返回值,通過以下宏查看操作結果operation result,self/OOPC_NULL#define OPRS(class) (class).self// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>#endif /* OOPC_H_ */

250行左右的所有宏設計。常見的面向對象設計方式都有,基本的設計要求都能滿足。

詳細的設計方式以及樣樣例可以查看上傳到百度網盤中文檔:

pan.baidu.com/s/1ggBngj 密碼:pfa8

推薦閱讀:

TAG:C編程語言 | 面向對象編程 |