c印记(二):lw_oopc简介
来源:互联网 发布:js混淆加密压缩 编辑:程序博客网 时间:2024/05/16 01:55
目录
- 目录
- 1 lw_oopc简介
- 2 lw_oopc 宏定义介绍
- 2_1 基础宏部分
- 2_1_1 CLASS
- 2_1_2 CTOREND_CTOR
- 2_1_3 DTOREND_DTOR
- 2_1_4 FUNCTION_SETTING
- 2_1_5 基础宏应用实例
- 2_2 ABS_CLASS扩展
- 2_2_1 概述
- 2_2_2 例子
- 2_3 INTERFACE扩展
- 2_3_1 概述
- 2_3_2 例子
- 2_1 基础宏部分
- 3 总结
1、 lw_oopc简介
在上一篇中简单的提了一下面向对象以及c语言实现面向对象,写得一塌糊涂,这里就不管了,本篇主要介绍lw_oopc这个东东。
lw_oopc是由高焕堂及其MISOO团队创作的(在《UML+OOPC嵌入式C语言开发精讲》一书中有相关介绍),本文说的lw_oopc并非《UML+OOPC嵌入式C语言开发精讲》中原版的lw_oopc,而是source forge上下 载的lw_oopc(在原版的基础上有经过优化和功能增加,如增加了ABS_CLASS(虚基类),且是以LGPL协议开源),其作者是 金永华,在其readme文档中有对两者(原版和这个1.2版本)的对比:
原有高焕堂先生及其MISOO团队创作的宏(总共6个宏),清单如下:
为了更好的支持面向对象以及面向接口编程,我(金永华)增加了14个宏:
2、 lw_oopc 宏定义介绍
由于篇幅所限,并一定会每个宏都做介绍,因为这些宏都比较简单,所以并不会过多的介绍宏本身,更多的是以使用角度来讲。
2_1 基础宏部分
2_1_1 CLASS
首先咱就来说说这个最基本的关键字(CLASS),在lw_oopc中CLASS这个宏定义如下:
#define CLASS(type) /*其中的type为所要定义的类名*/ \typedef struct type type; /*使用typedef定义一个名为‘type’的类名*/ \type* type##_new(lw_oopc_file_line_params); /*创建对象的函数,类似c++中的new*/ \void type##_ctor(type* t); /*类的构造函数声明*/ \int type##_dtor(type* t); /*类的析构函数声明*/ \void type##_delete(type* t); /*释放对象的函数,类似c++中的delete*/ \struct type /*名为‘type’的结构体定义*/
也以上一篇中Person类为例,定义如下:
CLASS(Person){ void (*Init)(struct Person* pPerson, int age, const char* name); void (*sayHello)(struct Person* pPerson); int mAge; char* mName;};
与上一篇中使用c语言的结构体来模拟类相比,这里就少了一个Uninit方法,因为这个方法的行为将在Person的析构函数中进行。至于ABS_CLASS和INTERFACE宏与CLASS基本类似,只是没有type##_new以及type##_delete方法。
2_1_2 CTOR/END_CTOR
这组宏用于定义类的构造函数,具体宏定义如下:
#define CTOR(type) \ type* type##_new() { /*实现创建对象的函数*/ \ struct type *cthis; \ cthis = (struct type*)malloc(sizeof(struct type)); /*为对象(即struct)分配内存*/ \ if(!cthis) \ { \ return 0; \ } \ type##_ctor(cthis);/*调用类的构造函数*/ \ return cthis; \} \ \void type##_ctor(type* cthis) {/*定义类的构造函数*/#define END_CTOR } /*类构造函数的结束大括号*/
CTOR宏中的malloc可以使用其他的接口函数代替,以便记录一些debug信息,在lw_oopc中在memory leak检测的时 候就会使用: lw_oopc_malloc(sizeof(struct type), #type, file, line);
代替malloc,他会记录类的名字,源码的文件名,以及在文件中的行号。
2_1_3 DTOR/END_DTOR
这组宏是在金永华创作的lw_oopc当中新增的,定义类的析构函数,与CTOR相对应:
#define DTOR(type) \void type##_delete(type* cthis) /*实现释放对象的函数*/ \{ \ if(type##_dtor(cthis)) /*调用类的析构函数*/ \ { \ lw_oopc_free(cthis);/*释放对象的内存*/ \ } \} \int type##_dtor(type* cthis) /*定义类的析构函数*/ \{#define END_DTOR } /*类析构函数结束大括号*/
2_1_4 FUNCTION_SETTING
这个宏用于注册成员函数,它的定义也比较简单,基本上就是一个赋值语句(当然,如果有需要的话也可以丰富这个宏的内容,让其功能更强大):
#define FUNCTION_SETTING(f1, f2) cthis->f1=f2;/*将成员函数赋值给struct中的函数指针*/
2_1_5 基础宏应用实例
以上几个定义和注册函数的使用方式如下:
/* 声明Person类 */CLASS(Person){ void (*Init)(struct Person* pPerson, int age, const char* name); void (*sayHello)(struct Person* pPerson); int mAge; char* mName;};/*定义成员函数,为了封装性,建议在.c档案中定义static类型的函数*/ static void init(struct Person* pPerson, int age, const char* name){ pPerson->mAge = age; pPerson->mName = name;/*为了简单表示,这里不去关心字符串内存问题*/}static void sayHello(struct Person* pPerson){ printf("hello, my name is:%s and i'm %d years old\n", pPerson->mName, pPerson->mAge);}/*定义构造函数*/CTOR(Person)cthis->mAge = 0;cthis->mName = NULL; /*初始化成员函数*/FUNCTION_SETTING(Init, init);FUNCTION_SETTING(sayHello, sayHello); /*注册成员函数*/END_CTOR/*定义析构函数*/DTOR(Person)//todo release member variablereturn lw_oopc_true; //如果需要释放对象就分会true,反之返回false(这样可以实现引用计数之类的应用)END_DTOR/*具体使用*/int main(int argc, char* argv[]){ Person* pPerson = Person_new(); /*创建Person的对象实例*/ pPerson->Init(pPerson, 12, "LiLei");/* 初始化对象 */ pPerson->sayHello(pPerson); Person_delete(pPerson); return 0;}
2_2 ABS_CLASS扩展
2_2_1 概述
ABS_CLASS宏对应于c++中的虚基类(因为只是c语言的宏,所以无法从语法规则上去约束其只是虚基类,也就是说具体使用的时候也可能将其作为普通的基类(即所有成员函数都有实现))。这个宏的作用就是可以让c语言实现继承以及多态。当然这里也有不少缺陷和约束,比如因为不是语法规则上的约束,所以无法在编译阶段就知道是不是所有成员函数都有对应的实现。
其宏定义和CLASS差不多,只是没有type##_new以及type##_delete方,所以这里就不在将其列出来了,下面就以一个例子来说明其使用方式。
2_2_2 例子
这里以lw_oopc的demo中关于动物的例子(会有适当的修改,详情请到lw_oopc的源码包中去查看),动物是一个基类,而狗,鱼等都属于动物,是动物的子类(is-a关系):
#include "lw_oopc.h"#include <stdio.h>ABS_CLASS(Animal)/*声明动物 基类*/{ char name[128]; // 动物的昵称(假设小于128个字符) int age; // 动物的年龄 void (*setName)(Animal* t, const char* name); // 设置动物的昵称 void (*setAge)(Animal* t, int age); // 设置动物的年龄 void (*sayHello)(Animal* t); // 动物打招呼 void (*init)(Animal* t, const char* name, int age); // 初始化昵称和年龄};CLASS(Fish) /*声明 鱼 类*/{ EXTENDS(Animal); // 继承Animal抽象类 void (*init)(Fish* t, const char* name, int age);};CLASS(Dog) /*声明 狗 类*/{ EXTENDS(Animal); // 继承Animal抽象类 void(*init)(Dog* t, const char* name, int age);};///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////* 设置动物的昵称 */void Animal_setName(Animal* t, const char* name){ // 这里假定name小于128个字符,为简化示例代码,不做保护(产品代码中不要这样写) strcpy(t->name, name);}/* 设置动物的年龄 */void Animal_setAge(Animal* t, int age){ t->age = age;}/* 动物和我们打招呼 */void Animal_sayHello(Animal* t){ printf("Hello! 我是%s,今年%d岁了!\n", t->name, t->age);}/* 初始化动物的昵称和年龄 */void Animal_init(Animal* t, const char* name, int age){ t->setName(t, name); t->setAge(t, age);}ABS_CTOR(Animal) /*定义 动物 类的构造函数,并注册成员函数*/FUNCTION_SETTING(setName, Animal_setName);FUNCTION_SETTING(setAge, Animal_setAge);FUNCTION_SETTING(sayHello, Animal_sayHello);FUNCTION_SETTING(init, Animal_init);END_ABS_CTOR//////////////////////////////////////////////////////////////////* 初始化鱼的昵称和年龄 */void Fish_init(Fish* t, const char* name, int age){ Animal* animal = SUPER_PTR(t, Animal); animal->setName(animal, name); animal->setAge(animal, age);}CTOR(Fish)/*定义 鱼 类的构造函数,并注册成员函数*/SUPER_CTOR(Animal);FUNCTION_SETTING(init, Fish_init);END_CTOR/////////////////////////////////////////////////////////////////* 初始化狗的昵称和年龄 */void Dog_init(Dog* t, const char* name, int age){ Animal* animal = SUPER_PTR(t, Animal); animal->setName(animal, name); animal->setAge(animal, age);}CTOR(Dog)/*定义 狗 类的构造函数,并注册成员函数*/SUPER_CTOR(Animal);FUNCTION_SETTING(init, Dog_init);END_CTOR//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////int main(int argc, char* argv[]){ Fish* fish = Fish_new(); // 创建鱼对象 Dog* dog = Dog_new(); // 创建狗对象 Animal* animal = NULL; // 初始化鱼对象的昵称为:小鲤鱼,年龄为:1岁 fish->init(fish, "小鲤鱼", 1); // 初始化狗对象的昵称为:牧羊犬,年龄为:2岁 dog->init(dog, "牧羊犬", 2); // 将fish指针转型为Animal类型指针 animal = SUPER_PTR(fish, Animal); animal->sayHello(); // 将dog指针转型为Animal类型指针 animal = SUPER_PTR(dog, Animal); animal->sayHello(); lw_oopc_delete(fish); lw_oopc_delete(dog); return 0;}
从上面的例子可以看出,c模拟面向对象毕竟不是原生支持,必然会有很多缺陷和约束,比如这个狗类中继承动物类的sayHello函数,就无法使用dog对象去调用,必须将其转换为animal对象方能调用。
这里的继承其实可以用在c的模块开发当中,ABS_CLASS定义模块的接口,CLASS再定义各种子模块,比如设计一个stream模块(各种流操作),就可以使用ABS_CLASS定义出stream模块的对外接口,以及一些stream模块内部各个子模块可共用的接口,然后在stream模块就可以使用CLASS去定义一些具体的子模块,如本地文件CLASS(FileStream),网络文件CLASS(HttpStream)等等。
2_3 INTERFACE扩展
2_3_1 概述
这个概念应该源自java中的interface,以interface 关键字定义一套接口方法(这里只有方法的声明,没有实现 ),然后再在具体的类中去实现这些接口方法。
那么问题就来了,既然有了ABS_CLASS,那还要INTERFACE干嘛呢? 就以lw_oopc的demo中的例子来说,动物,除了有呼吸,吃东西等行为之外,还有一个共同的特征就是“移动”。如 果以ABS_CLASS的方式实现的话,就会在Animal类中定义一个move方法。
那是不是只有动物才会“移动”呢? 显然不是,最常见的比如汽车,也是会移动的物体,当它却不是动物,如果以 ABS_CLASS方式实现,那么就需要在Animal和Car类中都声明move方法,为何要如此呢? 这是因为动物和汽车是不 同的类别。
当然这里还有另一种实现方式——INTERFACE,move是一种抽象的行为,谁有这种行为,就去实现这个INTERFACE,汽车能够移动,那么汽车类就去实现汽车的移动方式,动物能够移动,那动物类就去实现动物的移动方式。
2_3_2 例子
这里还是以lw_oopc中的例子来说明 INTERFACE的具体应用:
#include "lw_oopc.h"#include <stdio.h>INTERFACE(IMoveable){ void (*move)(IMoveable* t); // Move行为};/*这里为了简单,就不用Animal基类了*/CLASS(Fish){ IMPLEMENTS(IMoveable); // 实现IMoveable接口 void (*sayHello)(Fish* t); // 动物打招呼 void (*init)(Fish* t, const char* name, int age); char name[128]; // 动物的昵称(假设小于128个字符) int age; // 动物的年龄};///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////* 鱼的移动行为 */void Fish_move(IMoveable* t){ printf("鱼在水里游!\n");}/* 初始化鱼的昵称和年龄 */void Fish_init(Fish* t, const char* name, int age){ // 这里假定name小于128个字符,为简化示例代码,不做保护(产品代码中不要这样写) strcpy(t->name, name); t->age = age;}/* 动物和我们打招呼 */void Fish_sayHello(Fish* t){ printf("Hello! 我是%s,今年%d岁了!\n", t->name, t->age);}CTOR(Fish)/*定义 鱼 类的构造函数,并注册成员函数*/FUNCTION_SETTING(IMoveable.move, Fish_move);FUNCTION_SETTING(init, Fish_init);FUNCTION_SETTING(sayHello, Fish_sayHello);END_CTOR//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////int main(int argc, char* argv[]){ Fish* fish = Fish_new(); // 创建鱼对象 IMoveable* moveObj = NULL; // 初始化鱼对象的昵称为:小鲤鱼,年龄为:1岁 fish->init(fish, "小鲤鱼", 1); //鱼打招呼 fish->sayHello(); // 将fish指针转型为IMoveable接口类型指针 moveObj = SUPER_PTR(fish, IMoveable); //鱼移动 moveobj->move(); lw_oopc_delete(fish); return 0;}
3、 总结
从以上简介可以看出,虽然其可以模拟面向对象编程,但显然其中有不少缺陷和约束。而且这些宏的功能虽然基本的都有了,用于简单的学习是完全足够,但如果要用于实际的开发项目,可能就还需要更多的功能扩展和优化(这个下一章会有相关说明),现在我们来总结一下lw_oopc宏的一些优缺点(都是寡人的门户之见,并不一定正确,如有不同看法,欢迎拍砖):
- 优点:
1. 比较简洁,基本上一看就懂,学习曲线比较平缓;
2. 能在一定程度上实现面向对象编程;
3. 有利于功能模块以及子模块的划分和隔离。
- 缺点:
1. 功能还不完善,需要进一步增强和优化才能更好的用于实际项目;
2. 由于是使用的宏定义,会使用预处理机制,所以在这些宏定义中就无法在编译时进行类型检测;
3. 由于是模拟的面向对象编程,所以没有原生支持的编程语言使用起来方便;
4. 无法在编译时就检测成员函数是否已经实现,如未实现,就会在运行时产生segmentation fault错误。
5. 阅读不方便,如source insight这样的工具,无法判断以CLASS等宏定义的结构体,在阅读以 及代码跳转查看的时候不太方便
- c印记(二):lw_oopc简介
- c印记(一):面向对象
- c印记(八): ring buffer实现
- c印记(三): my_oopc
- c印记(四): 递归
- c印记(五):数组
- c印记(十四):跨平台线程封装
- LW_OOPC.H 面向对象C MISOO 头文件
- 大数据系列二(1)---时代的印记(互联网,云计算)
- c印记(十三):表驱动编程——优美的逻辑优化者
- c印记(七): ini file解析
- 关于lw_oopc
- C-TPAT认证简介(二)
- 大数据系列二(2)---时代的印记(大数据时代,大数据与社会治理)
- {C语言}之 轻量级的面向对象 C编程 框架 LW_OOPC
- c印记(六): 数组与递归联合应用的小游戏
- c印记(十一): 单向链表 list原理与实现
- c印记(十二):队列queue原理与实现
- hdu5366 The mook jong (DP)
- Android Studio Package 问题和解决
- 斐波那契数列 catalan
- 【Flash逆向调试之一】环境搭建
- oracle11g 建立全文索引
- c印记(二):lw_oopc简介
- Python实现向solrclould提交pdf文件
- EasyDarwin调研报告
- MySQL的if,case语句使用总结
- IntelliJ IDEA 15激活码(破解)
- Android 记住密码和自动登录界面的实现
- D - Multiplication Puzzle
- mongodb学习1(基础知识)
- SO_KEEPALIVE选项