OOC-GCC 特性介绍

OOC-GCC 特性介绍

•核心部分仅仅是”宏”,所以编译的时候更加灵活.

•两层宏定义,底层的”宏”完全采用英文全称,表意清晰.同时严格控制每个宏的定义,尽力做到不烂用.

•对于OO的模拟有构造也有析构,宏的定义具有对称性,同时符合语言规则,如表述表示 类的”名词” + 表示方法的”动词+名词”.

•类的定义多数采用全开放的形式,这也使得现在的版本和VC兼容.

•方便和C++的配合.

•相对完整的类空间与实例(对象)空间的模拟,类空间的构造和析构通过类似引用计数的方法对开发者”透明”.

•相对完整的单根继承的模拟,无需的在子类的构造/析构函数中显示地调用父类的构造/析构函数.

•和主流C编译工具兼容,无论GCC或是M$的编译工具都可无warning编译通过.

    —-实际测试为GCC 32bit 4.5.2 MinGW环境以及Ubuntu环境,64bit的找别人帮忙测试过,可能会有几个关于size_t的warning

    —–微软的是编译器  32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80×86

    —–微软的是编译器  32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80×86

•提供较为便利的调试层(仅针对GCC),

    —-提供更加方便的断言宏

    —-提供针对纯C的异常捕获机制的模拟

    —-提供和堆内存分配的日志监测

    —-提供仪表函数(就是监控每一个函数的调用)日志监测

    —-提供手动调用日志监测

    —-日志输出格式较为简洁,配合addr2line及graphviz等工具可以较为方便的生成图表

•提供一些常规的函数(这一部分是独立出来的)

•文件结构较为简洁,且功能上比较独立,同时有OOCfg.h中定义了一些宏开关方便一些特性的开启与停用.

•提供独立的单文件宏OOC.h,方便Release版的使用.

•提供了一些测试用例,以及在win下配合MinGW及VC编译用的批处理,*nix的GCC使用时改一下即可

————————————————————————————————————————————-

关于OOC-GCC中宏的使用

类的设计(模块化的编程应在.h文件中使用)

 
假定有一个名为"A""类"

CLASS(A){
    ......  这里为实例成员
    STATIC(A);
    ......  这里是类成员(实际结构体为struct _StA,并被重定义为StA)
};

假定有一个名为"B"的继承了上面"B""类"

CLASS_EX(A,B){
    .......
    STATIC_EX(A,B);
    .......
};

注意继承时,前面是父类,后面是要定义的子类.

类的构造与析构(模块化的编程应在.c文件中使用)

static int A_reload(A *THIS,void *p){
        THIS->.... 这里使用第一个参数来初始化实例成员
        return 0;
}
static int A_reloadSt(StA *THIS,void *p){
        THIS->.... 这里使用第一个参数来初始化类成员
        return 0;
}
static int A_unload(A *THIS,void *p){
        THIS->.... 这里使用第一个参数来析构实例成员
        return 0;
}
ASM(A,A_reload,A_unload,A_reloadSt,NULL)
注意上面最后一个参数为类成员的析构
使用NULL是为了说明无需某个函数时,可以不设置

类的使用

普通类"A"的使用
A *a=NEW0(A);  //声明第一个A的实例时调用StA和A的构造,
               //以后再声明A的实例只调用A的构造
StA *fA=ST(a);
fA->someFunc(a,someParam);
DELETE0(a);    //销毁A的实例时调用A的析构
               //当销毁显存的最后一个A的实例时,
               //调用A和StA的构造

带有继承的类"B"的使用
B *b=NEW0(B);   //注意父类的构造会自动调用
StB *fB=ST(b);
fB->someFunc(b,someParam);
StA *fA=ST(b);
fA->someFunc(b,someParam); 使用父类的方法
DELETE0(b);  //无需知道b的具体类型时A或B,都会调用正确的析构
             //如果是A的指针,则调用A的析构,如果是B的指针则调用B和A的析构

——————————————————————————————————————————————————–

关于OOC-GCC中单根继承的说明

假设我们定义四个类,A,B,C,D,并且后面的类继承前面的类,则有


CLASS(A){
        STATIC(A);
};
static int A_reload(A *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int A_unload(A *THIS,void *PARAM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int A_reloadSt(StA *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int A_unloadSt(StA *THIS,void *PARAM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
ASM(A,A_reload,A_unload,A_reloadSt,A_unloadSt)

CLASS_EX(A,B){
        STATIC_EX(A,B);
};
static int B_reload(B *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int B_unload(B *THIS,void *PBRBM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
int B_reloadSt(StB *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int B_unloadSt(StB *THIS,void *PBRBM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
ASM_EX(A,B,B_reload,B_unload,B_reloadSt,B_unloadSt)

CLASS_EX(B,C){
        STATIC_EX(B,C);
};
static int C_reload(C *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int C_unload(C *THIS,void *PCRCM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int C_reloadSt(StC *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int C_unloadSt(StC *THIS,void *PCRCM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
ASM_EX(B,C,C_reload,C_unload,C_reloadSt,C_unloadSt)

CLASS_EX(C,D){
        STATIC_EX(C,D);
};
static int D_reload(D *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int D_unload(D *THIS,void *PDRDM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int D_reloadSt(StD *THIS,char *name){
        printf("%s\n",__FUNCTION__);
        return 0;
}
static int D_unloadSt(StD *THIS,void *PDRDM){
        printf("%s\n",__FUNCTION__);
        return 0;
}
ASM_EX(C,D,D_reload,D_unload,D_reloadSt,D_unloadSt)

上面的代码再调用相关的函数是会打印出对应的__FUNCTION__,

        printf("\n*****************NEW A\n");
        A *a=NEW0(A);
        printf("\n*****************NEW B\n");
        B *b=NEW0(B);
        printf("\n*****************NEW C\n");
        C *c=NEW0(C);
        printf("\n*****************DEL C\n");
        DELETE0(c);
        printf("\n*****************DEL B\n");
        DELETE0(b);
        printf("\n*****************DEL A\n");
        DELETE0(a);
        printf("\n*****************NEW D\n");
        D *d=NEW0(D);
        printf("\n*****************DEL D\n");
        DELETE0(d);

如果像上面这样调用,则会有如下输出

*****************NEW A
A_reloadSt
A_reload

*****************NEW B
A_reload
A_reloadSt
B_reloadSt
B_reload

*****************NEW C
A_reload
B_reload
A_reloadSt
B_reloadSt
C_reloadSt
C_reload

*****************DEL C
C_unload
B_unload
A_unload
A_unloadSt
B_unloadSt
C_unloadSt

*****************DEL B
B_unload
A_unload
A_unloadSt
B_unloadSt

*****************DEL A
A_unload
A_unloadSt

*****************NEW D
A_reloadSt
A_reload
A_reloadSt
B_reloadSt
B_reload
A_reloadSt
B_reloadSt
C_reloadSt
C_reload
A_reloadSt
B_reloadSt
C_reloadSt
D_loadSt
D_load

*****************DEL D
D_unload
C_unload
B_unload
A_unload
A_unloadSt
A_unloadSt
B_unloadSt
A_unloadSt
B_unloadSt
C_unloadSt
A_unloadSt
B_unloadSt
C_unloadSt
D_unloadSt

构造的时候遵循先父再子,析构的时候遵循先子再父.

另外关于静态部分的使用,在某个类第一次使用时自动的调用静态构造

当销毁某个类的最后一个实例时自动的调用静态析构

Hello,OOC World![Chap2Sec1-3][GFDL]

项目地址(点击超链) OOC_GCC 

注意:OOC_GCC 源码以LGPL发布,文档为GFDL,文档相关测试用例为GPL3

Web版文档发布暂定为项目托管地SVN仓库,WikiPage,"这里",以及我的博客.

转载请注明出处


Hello,OOC World!

                ---- 原始作者: 大孟  pingf0@gmail.com


                                          崇 尚 开 源 , 热 爱 分 享 !  


这份Tutorial性质的文档其实很扯的,非要啰嗦些用C语言进行面向对象开发的基本内容

 

版权说明

License Type: GFDL

Copyright (C) 2011-2011 Jesse Meng  pingf0@gmail.com
Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation;with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.A copy of the license is included in the section entitled “GNU Free Documentation License”.

OOC-GCC为开源软件,遵循LGPL3协议发布,本手册为相关配套文档,采用GFDL协议发布,本手册中提供的相关示例代码以及简化版的OOC-LITE 需遵循GPL3协议.任何使用请遵循相关协议, 如有和协议相冲突的特殊要求, 请联系我[ pingf0@gmail.com ]

第二章 { 伸展运动 }

 

 

 


 

1. < CLASS,CTOR,DTOR >

宏是一个十分强大的特性,某些人的观点是通过宏实际上我们可以创立一个新的语言!当然个人认为只是形式上罢了.不过通过宏,代码看起来真的可以很简洁,很强大.比如下面所介绍的,将用一些简单的宏让C代码看上去有点C++的味道.


#include "OOC.h"
CLASS(A){
        int a;
        void (*showA)(A *);
};
static void A_showA(A *THIS){
        printf("the value of obj's a is %d\n",THIS->a);
}
CTOR(A){
        THIS->a=100;
        THIS->showA=A_showA;
}
DTOR(A){
        THIS->a=0;
        THIS->showA=NULL;
}
int main(){
        A * obj=newA();
        obj->showA(obj);
        delA(&obj);
        return 0;
}

这个例子中用到了三个宏,分别是CLASS,CTOR(对应CONSTRUCTOR),DTOR(对应DESTRUCTOR). 如果把他们展开,其实和前面”对称之美”一节中的代码是一样的.但又不一样,因为使用了宏,可读性大大提高, 而代码量大大减少(上面的代码和上一章中的对比减少了约1/3)!这只是一个简单的类的模拟,如果类比较多且继生关系比较复杂, 那么节省的代码量还是相当可观的.

 

不过这里还是要再次强调一下,宏是好东西,但如果滥用反而会使可读性大大降低,难懂不说,还不利于以后的维护.

关于本手册中的宏的设计,我尽量做到简单明了,易于记忆.

 

闲话少扯,现在具体来看一下CLASS,CTOR和DTOR宏具体是怎么实现的.

#include <stdio.h>
#include <stdlib.h>
#define CLASS(Type) \
typedef struct _##Type Type; \
void ini##Type(struct _##Type *); \
void fin##Type(struct _##Type *); \
Type * new##Type(); \
void del##Type(struct _##Type **); \
struct _##Type

#define CTOR(Type) \
Type * new##Type() { \
    Type *THIS; \
    THIS=(Type*)calloc(1,sizeof(Type)); \
    if( NULL==THIS ) { \
        return NULL; \
    } \
    ini##Type(THIS); \
    return THIS; \
} \
void ini##Type(Type * THIS)

#define DTOR(Type) \
void del##Type(Type **THIS) { \
    fin##Type(*(THIS)); \
    free(*(THIS)); \
    (*(THIS))=NULL; \
} \
void fin##Type(Type *THIS)

没错,就是这么简单!(当然如果你觉得这都算复杂了话,还是不要继续下面的文字了,这是我目前能做到的最简化的宏了)

下一节将会闲扯一些为什么这样设计,以及仅仅是这样还有那些不足.

 

2. < 从CLASS说起 >

 

C语言中直接使用结构体其实是件很麻烦的事,因为每次声明都要使用额外的”struct”来声明.一些初学C的人,特别从VC开始入门那些,总会分不清什么是C,什么是C++.特别是在struct声明这一块也特别容易按照懒省事儿的方法来写.但是我们应该知道一些事情—-真正的纯C编译器如果不事先typedef一下是无法声明一个自定的结构体的实例的.

下面看一小段代码,演示如何将typedef与struct来结合.

typedef struct {int a;} A;
int main(){
        A obj;
        ojb.a=1;
        return 0;
}

关于typedef的语法,如果不牵扯结构体,是比较好理解的,比如”typedef int bool;”就是将原有的int型重定义为一个全新的bool型,尽管本质上它们是一样的.而一旦与结构体结合,就略微有些绕了.为了简化说明它的语法,上面的代码我做了一些处理,一是结构体本身匿名话,二是简化结构体内容并将其写到一行之内.这样我们看上去会十分明了还是”typedef struct … A;”的形式,而”…”中我们其实定义了一个结构体的内容,只不过这个结构体本身是”匿名的”.

更加常规的写法是,像下面这样.

typedef struct _A A;
struct _A{
        int a;
};
int main(){
        A obj;
        ojb.a=1;
        return 0;
}

CLASS宏中,也使用了和上面类似的做法来简化struct声明实例时的步骤.

#define CLASS(Type) \
typedef struct _##Type Type; \
void ini##Type(struct _##Type *); \
void fin##Type(struct _##Type *); \
Type * new##Type(); \
void del##Type(struct _##Type **); \
struct _##Type

CLASS宏不但简化了struct声明实例的工作,还声明了”四大函数“(将函数声明放在最前面是有好处的,它会让编译器在一开始就知道有这么些类型的函数).这四个函数其实是”两队”,一对是ini和fin打头,另一对是new和del打头.其分别对应栈内存和堆内存上实例的构造与析构.

而CLASS宏的最后则是一个全开放的形式(这里的全开放是指某个宏不需要语气配合相对应的”截止”宏来保护一段代码),开头和结尾都是用C语言自身的”{“和”}”符合来指明.

在下一节,将会介绍用于构造和析构的CTOR和DTOR宏,而它们则封装了”四大函数“的具体实现.

 

3. < CTOR & DTOR >

这一节来说一下用于模拟构造函数的宏CTOR以及用于模拟析构函数的宏DTOR.先回顾下CTOR的定义.

#define CTOR(Type) \
Type * new##Type() { \
    Type *THIS; \
    THIS=(Type*)calloc(1,sizeof(Type)); \
    if( NULL==THIS ) { \
        return NULL; \
    } \
    ini##Type(THIS); \
    return THIS; \
} \
void ini##Type(Type * THIS)

假设我们还是要定义一个名为”A”的类,那么上面的代码中我们要把”Type”换成”A”,并删除”##”(注意##在宏的使用中表示”连结”).这样的话,我们就看到了一个完整的”newA”函数和一个没有写完的”iniA”函数(请参考上一节最后的”四大函数“一说).

“iniA”函数实际上是真正的构造函数,其负责一个”类”成员的初始化.但其没有写完,因为具体如何初始化是由我们自己说了算的,我们可以在其后面紧跟着写上”{ THIS->a=1; }”(假设A类中有int型成员变量a),这样就完成了一个简单的构造函数的实现.

我们要注意的是iniA函数要接受一个类实例指针,然后再对其进行初始化.也就是说这个函数本身是不涉及内存的分配的,我们可以传入一个指向栈内存的指针,也可以传入一个指向堆内存的指针,它都会对其进行”初始化”!但是如果我们使用堆内存,还要先定义一个指针,并指向一块malloc返回的内存再传入ini函数,这多少有些麻烦.为了方便的使用堆内存,上面的CTOR宏还给出了一个new函数,这里仍以一个名为”A”的类为例.newA就将malloc函数和iniA函数和二为一!我们使用的时候只需像”A * obj=newA();”这样即可,这大大方便了堆实例的使用!

不难发现,newA就是对iniA的一个简单封装,其做的工作就是”1.分配堆内存.2.调用ini函数.3.返回一个指向已分配内存的指针.”这三块工作,这是有章可循的.也正因此,我们将其完全封装在CTOR宏之中.使用的时候我们几乎感觉不到它的存在,直接new就好.

下面再来看一下用于析构的DTOR宏,

#define DTOR(Type) \
void del##Type(Type **THIS) { \
    fin##Type(*(THIS)); \
    free(*(THIS)); \
    (*(THIS))=NULL; \
} \
void fin##Type(Type *THIS)

这里面定义了”四大函数“中用于析构的del函数和fin函数.其分别对应着前面的new函数和ini函数.我们可以对比着前面的讲述来理解.ini函数是真正的构造函数,fin函数是真正的析构函数.new是ini函数的一个封装,其做的具体工作就是先malloc在ini,del则是fin函数的一个封装,其做的具体工作是先fin再free.

当然因为有了new函数和del函数这样针对堆内存的封装,ini函数和fin函数更多的时候是与栈内存来配合使用的.

总的来看CTOR宏和DTOR宏,将涉及内存分配的部分独立出来可谓好处多多,不但可以更加自由且明确的使用栈内存和堆内存,还使得用于构造和析构的宏也能保持和前面CLASS宏一样的”全开放性”,同时CTOR宏和DTOR宏几乎是完全对称的,这意味着我们只需理解一半,另一半就迎刃而解了.

 



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值