正文

纯C也要继承,封装2008-08-15 13:16:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/sgpro/37613.html

分享到:

最近要在mtk平台上开发一套中间层,类似于MFC或者vcl的framework, 但是只能用纯C写,MTK本身就使纯C的,对于这个framework。 层次其实是很明晰的,习惯了封装继承思想便觉得纯C也要继承,封装。 下面就 object - Rect - Wnd - Button的单继承关系进行展示,说实话,目前为止我也只能实现单继承,java的单继承是不是也是这样弄,不得而知。 文件 CObject.h  包含 Object的对外声明 #ifndef  _OBJECT#define  _OBJECT typedef struct st_Object { void (*Dispose)(void*);    // 销毁对象方法 char*(*ToString)(void*, char*);  // toString方法 int  (*Init)(void*);    // 初始化方法 }Object; Object* new_Object(); #endif C的方法没有private,所以在Object中声明的都是public方法,至于private方法,在它的实现中可以体现出来, static函数便无法对外访问,实现了封装 文件 CObject.C 是 Object的实现 #include <malloc.h>#include <stdio.h>#include "CObject.h" static void  st_Object_Dispose(void* Handle);static int   st_Object_Init(void* Handle);static char* st_Object_ToString(void* Handle, char* Buffer); static void st_Object_Dispose(void* Handle){ Object** This = (Object**)Handle;  free(*This); *This = NULL;} static int st_Object_Init(void* Handle){ Object* This = (Object*)Handle;  This->Dispose  = st_Object_Dispose; This->ToString = st_Object_ToString; This->Init  = st_Object_Init;  return 1;} static char* st_Object_ToString(void* Handle, char* buffer){   sprintf(buffer, "This is a Object, The address is : %08X", Handle); return buffer;} Object* new_Object(){ Object *This = (Object*)malloc(sizeof(Object)); st_Object_Init(This);  return This;} 可以看出,除new_Object() 方法姑且称为构造方法之外的所有方法的实现都打上了static,不对外开放,只有通过Object内声明的方法来访问,对外来说该类封装了这些方法。而且不是所有的方法都会对外开放,只有Object内声明的才对外开放。 下面重点看看单继承 // CRect.h 文件 #ifndef _RECT#define _RECT#define PRIVATE static #include "CObject.h" // Rect 类typedef struct st_Rect{ // 继承基类 Object Object obj;  // 属性 int left; int top; int width; int height;  //继承基类Object的方法申明 void (*Dispose)(void*);  // 方法 int (*Init)(void*); int (*GetLeft)(void*); int (*GetTop)(void*); int (*GetWidth)(void*); int (*GetHeight)(void*); int (*GetRight)(void*); int (*GetBottom)(void*); int (*IsValid)(void*); int (*SetLeft)(void*, int); int (*SetTop)(void*, int); int (*SetWidth)(void*, int); int (*SetHeight)(void*, int); char* (*ToString)(void*, char*); }Rect; // Rect类的构造Rect* new_Rect(); #endif 注意,单继承的父类一定要定义在子类的第一个属性上,否则子类到父类的转化是无法完成的。 // CRect.C  CRect类的实现 #include <stdio.h>#include <malloc.h> #include "CObject.h"#include "CRect.h" // Rect类 方法申明static char* st_Rect_ToString(void* THIS, char* buffer);static int st_Rect_SetLeft(void *THIS, int left);static int st_Rect_SetTop(void *THIS, int top);static int st_Rect_SetWidth(void *THIS, int width);static int st_Rect_SetHeight(void *THIS, int height);static int st_Rect_GetLeft(void *THIS);static int st_Rect_GetTop(void *THIS);static int st_Rect_GetWidth(void *THIS);static int st_Rect_GetHeight(void *THIS);static int st_Rect_GetRight(void *THIS);static int st_Rect_GetBottom(void *THIS);static int st_Rect_IsValid(void *THIS);static int st_Rect_Init(void *THIS); // Rect类 方法实现static char* st_Rect_ToString(void* THIS, char* buffer){  Object Base = ((Rect*)THIS)->obj; char temp[256];  sprintf(buffer, "This is Rect, left: %d; top:%d; height:%d; width:%d valid:%s\n[Object Inf]: %s",  ((Rect*)THIS)->left,  ((Rect*)THIS)->top,  ((Rect*)THIS)->height,  ((Rect*)THIS)->width,  ((Rect*)THIS)->IsValid(((Rect*)THIS))? "TRUE":"FALSE",  Base.ToString(&Base, temp)); return buffer;} static int st_Rect_SetLeft(void *THIS, int left){  return ((Rect*)THIS)->left = left;} static int st_Rect_SetTop(void *THIS, int top){   return ((Rect*)THIS)->top = top;}static int st_Rect_SetWidth(void *THIS, int width){  return ((Rect*)THIS)->width = width;}static int st_Rect_SetHeight(void *THIS, int height){ return ((Rect*)THIS)->height = height;} static int st_Rect_GetLeft(void *THIS){ return ((Rect*)THIS)->left;} static int st_Rect_GetTop(void *THIS){ return ((Rect*)THIS)->top;}static int st_Rect_GetWidth(void *THIS){ return ((Rect*)THIS)->width;}static int st_Rect_GetHeight(void *THIS){ return ((Rect*)THIS)->height;}static int st_Rect_GetRight(void *THIS){ return ((Rect*)THIS)->left + ((Rect*)THIS)->width;}static int st_Rect_GetBottom(void *THIS){ return ((Rect*)THIS)->top + ((Rect*)THIS)->height;}static int st_Rect_IsValid(void *THIS){ return ((Rect*)THIS)->width >= 0 && ((Rect*)THIS)->height >= 0;}   static int st_Rect_Init(void *THIS){ // 基类构造 Object* Base = new_Object(); ((Rect*)THIS)->obj = *Base;  // 继承基类Object的方法 ((Rect*)THIS)->Dispose = Base->Dispose;  ((Rect*)THIS)->left = 0; ((Rect*)THIS)->top = 0; ((Rect*)THIS)->height = 0; ((Rect*)THIS)->width = 0;  ((Rect*)THIS)->SetHeight = st_Rect_SetHeight; ((Rect*)THIS)->SetLeft   = st_Rect_SetLeft; ((Rect*)THIS)->SetTop    = st_Rect_SetTop; ((Rect*)THIS)->SetWidth  = st_Rect_SetWidth;  ((Rect*)THIS)->GetBottom = st_Rect_GetBottom; ((Rect*)THIS)->GetHeight = st_Rect_GetHeight; ((Rect*)THIS)->GetLeft   = st_Rect_GetLeft; ((Rect*)THIS)->GetRight  = st_Rect_GetRight; ((Rect*)THIS)->GetTop    = st_Rect_GetTop; ((Rect*)THIS)->GetWidth  = st_Rect_GetWidth; ((Rect*)THIS)->Init      = st_Rect_Init; ((Rect*)THIS)->IsValid   = st_Rect_IsValid; ((Rect*)THIS)->ToString  = st_Rect_ToString;  return ((Rect*)THIS)->IsValid(((Rect*)THIS));} // Rect类的构造Rect* new_Rect(){ Rect* ret = (Rect*)malloc(sizeof(Rect));  st_Rect_Init(ret);  return ret;} 也许你会发现,为什么CObject内的方法和CRect的方法,对象句柄指针This都定义成void*型,原因在于这些类都有可能被继承,一旦被继承,就必须要能处理该系列的所有对象句柄,也就是说,它的子类对象的句柄调用这个方法的时候,也要能处理。这是向下兼容原则的实现,也是继承的理论的基础。 下面几个类都是使用以上原则,不过在此可以看出单继承不是发生一次,是可以不停传递下去的,比如CButton类的 Dispose方法,最终调用的也是多级父类CObject的逻辑。 // CWnd.h #ifndef _WND#define _WND #include "CRect.h" // Wnd类,基类为Recttypedef struct st_Wnd{ Rect rt; char text[256];  // 基类Rect方法申明 void (*Dispose)(void*);  int (*GetLeft)(void*); int (*GetTop)(void*); int (*GetWidth)(void*); int (*GetHeight)(void*); int (*GetRight)(void*); int (*GetBottom)(void*);  int (*IsValid)(void*);  int (*SetLeft)(void*, int); int (*SetTop)(void*, int); int (*SetWidth)(void*, int); int (*SetHeight)(void*, int);  //  方法申明 int (*Init)(void*); int (*SetText)(void*, char*); char* (*GetText)(void*);  char* (*ToString)(void*, char*);}Wnd; // Wnd类的构造方法Wnd* new_Wnd(); #endif // CWnd.c #include <string.h>#include <stdio.h>#include <malloc.h> #include "CWnd.h" // Wnd 成员方法的申明static char* st_Wnd_GetText(void* THIS);static int  st_Wnd_SetText(void* THIS, char* text);static char* st_Wnd_ToString(void* THIS, char* buffer);static int st_Wnd_Init(void* THIS); // Wnd 成员方法的实现static char* st_Wnd_GetText(void* THIS){ return ((struct st_Wnd*)THIS)->text;} static int  st_Wnd_SetText(void* THIS, char* text){ strcpy(((struct st_Wnd*)THIS)->text, text); return 0;} static char* st_Wnd_ToString(void* THIS, char* buffer){ Rect* Base = &(((struct st_Wnd*)THIS)->rt);  char temp[256]; sprintf(buffer, "This is window the text is: %s\n[Rect Inf]: %s",   ((struct st_Wnd*)THIS)->text,   Base->ToString(Base, temp)); return buffer;} static int st_Wnd_Init(void* THIS){   // 基类构造 Rect* Base = new_Rect(); ((struct st_Wnd*)THIS)->rt = *Base;  // 继承基类方法成员 ((struct st_Wnd*)THIS)->Dispose  = Base->Dispose; ((struct st_Wnd*)THIS)->GetBottom  = Base->GetBottom; ((struct st_Wnd*)THIS)->GetHeight  = Base->GetHeight; ((struct st_Wnd*)THIS)->GetLeft  = Base->GetLeft; ((struct st_Wnd*)THIS)->GetRight  = Base->GetRight; ((struct st_Wnd*)THIS)->SetHeight  = Base->SetHeight; ((struct st_Wnd*)THIS)->SetLeft  = Base->SetLeft; ((struct st_Wnd*)THIS)->SetTop  = Base->SetTop; ((struct st_Wnd*)THIS)->SetWidth  = Base->SetWidth; ((struct st_Wnd*)THIS)->IsValid = Base->IsValid;  // 方法成员初始化 ((struct st_Wnd*)THIS)->GetText = st_Wnd_GetText; ((struct st_Wnd*)THIS)->SetText = st_Wnd_SetText; ((struct st_Wnd*)THIS)->ToString  = st_Wnd_ToString;  // 属性成员初始化 strcpy(((struct st_Wnd*)THIS)->text , "");  return Base->IsValid(Base);} // Wnd类的构造方法Wnd* new_Wnd(){ Wnd* ret = (Wnd*)malloc(sizeof(Wnd));  st_Wnd_Init(ret);  return ret;} // CButton.h #ifndef _BUTTON#define _BUTTON#include "CWnd.h" // Button类, 基类为 Wnd类typedef struct st_Button{  // 成员变量 Wnd  wnd;   // 基类 int  style; // 风格  // 基类Wnd方法申明 void (*Dispose)(void*);  int (*GetLeft)(void*); int (*GetTop)(void*); int (*GetWidth)(void*); int (*GetHeight)(void*); int (*GetRight)(void*); int (*GetBottom)(void*);  int (*IsValid)(void*);  int (*SetLeft)(void*, int); int (*SetTop)(void*, int); int (*SetWidth)(void*, int); int (*SetHeight)(void*, int);  int (*SetText)(void*, char*); char* (*GetText)(void*);  // 方法申明 int (*Init)(void*); int (*GetStyle)(void*); void (*SetStyle)(void*, int);  char* (*ToString)(void*, char*); }Button;  // Button类的构造方法 Button* new_Button(); #endif   // CButton.c #include <stdio.h>#include <malloc.h>#include "CButton.h" // Button类方法的申明 static int st_Button_GetStyle(void *Handle); static void st_Button_SetStyle(void *Handle, int style); static char* st_Button_ToString(void *Handle, char* buffer); static int st_Button_Init(void* Handle); // Button类方法的实现static  int st_Button_GetStyle(void *Handle)  {  Button* THIS = (Button*)Handle;  return THIS->style; } static void st_Button_SetStyle(void *Handle, int style) {  Button* THIS =(Button*)Handle;  THIS->style = style; } static char* st_Button_ToString(void *Handle, char* buffer) {  Button* THIS = (Button*)Handle;  Wnd* Base = &(THIS->wnd);   char temp[256];   sprintf(buffer, "This is Button, The style is:%d\n[Window Inf]: %s",   THIS->style, Base->ToString(Base, temp));  return buffer;   }  static int st_Button_Init(void* Handle){  Button* THIS = (Button*)Handle;  // 基类构造  Wnd* Base = new_Wnd();   THIS->wnd = *Base;  // 基类函数初始化 THIS->Dispose   = Base->Dispose;  THIS->GetBottom  = Base->GetBottom; THIS->GetHeight  = Base->GetHeight; THIS->GetLeft  = Base->GetLeft; THIS->GetRight  = Base->GetRight; THIS->SetHeight  = Base->SetHeight; THIS->SetLeft  = Base->SetLeft; THIS->SetTop  = Base->SetTop; THIS->SetWidth  = Base->SetWidth; THIS->IsValid = Base->IsValid;  THIS->SetText = Base->SetText; THIS->GetText = Base->GetText;  THIS->Init  = st_Button_Init; THIS->SetStyle = st_Button_SetStyle; THIS->GetStyle = st_Button_GetStyle;    THIS->ToString  = st_Button_ToString;  // 变量初始化 THIS->style = 18;  return Base->IsValid(Base);}  // Button类的构造方法Button* new_Button(){ Button* ret = (Button*)malloc(sizeof(Button));  st_Button_Init(ret);  return ret;}   // Main.c // InHer.cpp : Defines the entry point for the console application.// 单继承 #include <stdio.h>#include <malloc.h>#include <string.h>#include <conio.h> #include "CRect.h"#include "CWnd.h"#include "CButton.h" int main(int argc, char* argv[]){ char temp[1024] = "";  Button* btn = new_Button();  // 调用基类Rect的方法 btn->SetTop(btn, 2343); btn->SetLeft(btn, 2782); btn->SetHeight(btn, 45); btn->SetWidth(btn, 598);  // 调用基类Wnd的SetText方法 btn->SetText(btn, "我爱你"); btn->SetStyle(btn, 99);  // 调用Button类自身的方法 puts(btn->ToString(btn, temp)); // 资源释放   btn->Dispose(&btn);  getch();  return 0;} // 运行结果 This is Button, The style is:99[Window Inf]: This is window the text is: 我爱你[Rect Inf]: This is Rect, left: 2782; top:2343; height:45; width:598 valid:TRUE[Object Inf]: This is a Object, The address is : 0012F850 也许有的人会提出疑问,虽然实现了继承,CButton可以调用CObject的方法,可是代码还有重复,在java中, 父类的方法是不需要再声明的,但是可以复写。 不错,但是在c当中,目前为止只能做到这点,再声明,再初始化。java内部是否也这样实现,难以考证,不过给程序员的感觉是不用再申明了。至于复写,我想上述每个类都有ToString方法,这也是重载的实现吧。还需指出一点就是,每个方法第一个参数都带了对象自身句柄,这就是面向对象语言中的This指针。 Copyright (C) 2008-8 sgpro  All rights reserved.  (谢绝转载)

阅读(2499) | 评论(1)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

loading...
您需要登录后才能评论,请 登录 或者 注册