LW_OOPC宏配置及使用指南_第1页
LW_OOPC宏配置及使用指南_第2页
LW_OOPC宏配置及使用指南_第3页
LW_OOPC宏配置及使用指南_第4页
LW_OOPC宏配置及使用指南_第5页
已阅读5页,还剩6页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

LW OOPC 宏配置及使用指南 金永华 2010 2 15 LW OOPC 是一套轻量级的面向对象 C 语言编程框架 它是一套 C 语言的宏 总共 1 个 h 文件 如果需要内存泄漏和调试打印支持 需要增加 1 个 c 文件 lw oopc c 约 145 行 20 个宏 约 130 行代码 非常的轻量级 但却很好的支持了很多面向对象的特性 比如继承 多态 可以优美的实现面向接口编程 注意 这里特别强调一下 使用 LW OOPC 的前提是 在 C 语言下 如果您所在的团 队已经在使用 C 那么 LW OOPC 对于这种情形是没有价值的 也就是说 LW OOPC 希望能够帮助到那些懂 OO 的程序员 即便是在用 C 语言编程 依然能够编写出面向对象 的程序 言归正传 本文将对 LW OOPC 的配置和使用方法进行讲解 并对这些宏逐个进行细 致讲解 期望本文能给希望在实践中应用 LW OOPC 的 C 程序员带来帮助 LW OOPC 当前版本共有两个文件 lw oopc h 和 lw oopc c LW OOPC 的使用非常 简单 只需要将这两个文件加入工程即可 常规情况下 建议用户同时使用上述两个文件 因为借助 lw oopc c 我们可以监测到内存泄漏 通过打开调试开关 我们能够观察内存分 配和释放的调试打印信息 这将有助于我们除错 减少调试的时间 如果你不需要监测内 存泄漏 譬如准备发布程序 此时 你并不需要 lw oopc c 而只需要 lw oopc h 即可 LW OOPC 配置配置 在 lw oopc h 中 有这么几行代码 配置宏 两种配置选其一 LW OOPC USE STDDEF OFFSETOF 表示使用C标准定义的offsetof LW OOPC USE USER DEFINED OFFSETOF 表示使用用户自定义的lw oopc offsetof宏 define LW OOPC USE STDDEF OFFSETOF define LW OOPC USE USER DEFINED OFFSETOF 是否支持内存泄露检测 缺省不支持 define LW OOPC SUPPORT MEMORY LEAK DETECTOR 从上边的注释 我们可以看出 LW OOPC 需要使用 offsetof 宏 如果你的开发环境 能够支持 C 标准定义的 offsetof 宏 那么什么都不需要动 如果你的开发环境不能支持 C 标准定义的 offsetof 宏 那么可以选择使用用户自定义的 lw oopc offsetof 宏 如果你的开 发环境连用户自定义的 offsetof 宏都不支持 在这种情形下 LW OOPC 将无法很好的支 持多态特性 很遗憾 你只能与 LW OOPC 失之交臂 关于LW OOPC对内存泄露检测以及调试打印的支持 我们将在LW OOPC高级配置高级配置 部分进行详细讲解 LW OOPC 宏说明宏说明 1 INTERFACE INTERFACE用于声明接口 譬如 INTERFACE IMoveable void move IMoveable t Move行为 在 LW OOPC 中 声明接口 抽象类和具体类的方法成员比较特殊 均是函数指针类型的 成员 事实上 LW OOPC 正是借助了函数指针的特性 完成了多态功能的模拟 2 ABS CLASS ABS CLASS用于声明抽象类 譬如 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 eat Animal t 动物都会吃 抽象方法 由子类实现 void breathe Animal t 动物都会呼吸 抽象方法 由子类 实现 void init Animal t const char name int age 初始化昵称和年龄 3 CLASS CLASS用于声明具体类 譬如 CLASS Fish EXTENDS Animal 继承Animal抽象类 IMPLEMENTS IMoveable 实现IMoveable接口 void init Fish t const char name int age 初始化昵称和年龄 在该例中 我们声明了Fish类 并让该类继承Animal抽象类 并且实现IMoveable接口 4 EXTENDS 和 IMPLEMENTS 在介绍CLASS宏的时候 我们在代码中看到有两个宏 EXTENDS和IMPLEMENTS 如果你查看lw oopc h的源码 你将会发现他们是一模一样的 define IMPLEMENTS type struct type type define EXTENDS type struct type type 之所以同时提供继承和实现关键字 仅仅是为了让熟悉Java的人更加容易理解 LW OOPC宏 注意 在LW OOPC中 建议将继承和实现声明写在结构体的开头 把继承和实现声明摆在显眼的位置 有助于阅读代码的人更好的理解代码 5 ABS CTOR 和 END ABS CTOR ABS CTOR和END ABS CTOR用于定义抽象类的构造函数 例如 设置动物的昵称 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 前面 我们声明Animal是一个抽象类 对应的构造函数定义需要使用ABS CTOR和 END ABS CTOR ABS CTOR是Abstract Constructor的缩写 6 FUNCTION SETTING 在介绍ABS CTOR和END ABS CTOR宏的时候 我们在代码中又发现一个陌生的宏 FUNCTION SETTING 这个宏在LW OOPC中的地位非同凡响 没有它 LW OOPC 就不可能存在 LW OOPC中的CTOR系列宏 CTOR END CTOR ABS CTOR END ABS CTOR 除了给对象 在C语言中是 struct 分配内存 然后 最重要的一个步骤是为结构体中的函数指针成员赋值 这一 过程 也可以称为函数绑定 有点类似C 中的动态联编 函数绑定的过程由 FUNCTION SETTING宏来完成 我们来看看FUNCTION SETTING宏是如何实现的 define FUNCTION SETTING f1 f2 cthis f1 f2 看到这里 想必读者应该会心一笑了 7 CTOR 和 END CTOR CTOR和END CTOR用于定义具体类的构造函数 例如 鱼的吃行为 void Fish eat Animal t printf 鱼吃水草 n 鱼的呼吸行为 void Fish breathe Animal t printf 鱼用鳃呼吸 n 鱼的移动行为 void Fish move IMoveable t printf 鱼在水里游 n 初始化鱼的昵称和年龄 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 Animal eat Fish eat FUNCTION SETTING Animal breathe Fish breathe FUNCTION SETTING IMoveable move Fish move FUNCTION SETTING init Fish init END CTOR 从代码上看 CTOR END CTOR 与 ABS CTOR END ABS CTOR 的使用方式完全相同 的确是 不过 背后 这两对宏的实现方式略有差异 建议有兴趣的读者 认真研究一下 LW OOPC 的源码 这里 简单地说明如下 我们希望明确区分抽象类和具体类的概念 抽象类是不可以创建对象的 而具体类则可以 前面 我们声明了 Animal 是抽象类 Fish 类是具体类 那么 我们希望 Animal animal Animal new 不允许这样写 Fish fish Fish new 允许这样写 8 SUPER CTOR 在讲解CTOR END CTOR宏的时候 又出现一个陌生的宏 SUPER CTOR 它的功能 与Java中的super关键字非常类似 SUPER CTOR Animal 意为 调用Animal类的构造函数 建议将SUPER CTOR写在 构造函数 体的开头 9 DTOR 和 END DTOR DTOR和END DTOR用于定义 析构函数 例如 Expr node的析构函数 DTOR END DTOR用于实现析构函数语义 DTOR Expr node if cthis use 0 递减引用计数 如果计数为 释放自己 cthis finalize cthis 释放内存之前先清理资源 其他需要释放的对象 lw oopc free cthis END DTOR 这里 特别说明一点 为了模拟C 中的this指针 我们允许用户在 ABS CTOR END ABS CTOR CTOR END CTOR DTOR END DTOR定义块中可以直接 使用cthis 10 SUPER PTR SUPER PTR用于 向上转型 将对象指针向上转型成直接父类或者直接接口 Fish fish Fish new 创建鱼对象 初始化鱼对象的昵称为 小鲤鱼 年龄为 1岁 fish init fish 小鲤鱼 1 将fish指针转型为Animal类型指针 并赋值给animals数组的第一个成员 Animal animal SUPER PTR fish Animal 将fish指针转型为IMoveable接口类型指针 并赋值给moveOjbs数组的第一个成员 IMoveable moveFish SUPER PTR fish IMoveable 这里 直接父类很容易理解 直接接口 呵呵 暂且认为我是首创的吧 我们再来看一下Fish类的声明代码 CLASS Fish EXTENDS Animal 继承Animal抽象类 IMPLEMENTS IMoveable 实现IMoveable接口 void init Fish t const char name int age 初始化昵称和年龄 看 IMPLEMENTS IMoveable 实现IMoveable接口 对Fish类来讲 IMoveable就是它的直接接口 11 SUPER PTR 2 和 SUPER PTR 3 SUPER PTR 2和SUPER PTR 3是SUPER PTR的高级版本 它们的作用与SUPER PTR 是完全类似的 都是向上转型 只不过 SUPER PTR 2是向上转两次 SUPER PTR 3是向上转三次 也就是说 SUPER PTR 2用于将自身的指针转型为爷 爷辈指针 SUPER PTR 3用于将自身的指针转型为曾祖辈指针 看看SUPER PTR 2 和SUPER PTR 3的代码 define SUPER PTR 2 cthis father grandfather SUPER PTR SUPER PTR cthis father grandfather define SUPER PTR 3 cthis father grandfather greatgrandfather SUPER PTR SUPER PTR 2 cthis father grandfather greatgrandfather 看到了吧 SUPER PTR 2其实是两次SUPER PTR的叠加 SUPER PTR 3是三次 SUPER PTR的叠加 由于转型两次或者转型三次 会使得程序过于复杂 所以 建议大家 合理组织类的继承关系 尽力避免使用二次转型和三次转型 12 SUB PTR SUB PTR用于 向下转型 将父类指针向下转型成子类 鱼的吃行为 void Fish eat Animal t Fish fish SUB PTR t Animal Fish 这里可以访问Fish类的成员 printf 鱼吃水草 n eat方法是Animal的一个方法 Fish类覆写了该方法 注意 由于该方法的第一个参数类型 是 Animal 在实现Fish类的eat方法Fish eat时 如果想要访问到Fish类的成员 需要将第 一个参数向下转型成Fish 这就是SUB PTR所完成的事情 13 SUB PTR 2 和 SUB PTR 3 SUB PTR 2和SUB PTR 3是SUB PTR的高级版本 它们的作用与SUB PTR是完全类 似的 都是向下转型 只不过 SUB PTR 2是向下转两次 SUB PTR 3是向下转三次 也就是说 SUB PTR 2用于将自身的指针转型为孙子辈指针 SUB PTR 3用于将自身 的指针转型为曾孙辈指针 看看SUB PTR 2和SUB PTR 3的代码 define SUB PTR 2 selfptr self child grandchild SUB PTR SUB PTR selfptr self child child grandchild define SUB PTR 3 selfptr self child grandchild greatgrandchild SUB PTR SUB PTR 2 selfptr self child grandchild grandchild greatgrandchild 看到了吧 SUB PTR 2其实是两次SUB PTR的叠加 SUB PTR 3是三次SUB PTR的叠加 由于转型两次或者转型三次 会使得程序过于复杂 所以 建议大家合理组织类的继承关 系 尽力避免使用二次转型和三次转型 14 INHERIT FROM INHERIT FROM用于访问直接父类的成员 例如 Dog dog Dog new 创建狗对象 初始化狗对象的昵称为 牧羊犬 年龄为 2岁 dog init dog 牧羊犬 2 INHERIT FROM Animal dog age 3 把牧羊犬的年龄修改为3岁 printf 狗的年龄是 d岁 n INHERIT FROM Animal dog age 打印狗的年龄 注意 LW OOPC的上一个版本 我们同时提供了INHERIT FROM 2和INHERIT FROM 3 这两个宏 INHERIT FROM 2用于访问爷爷辈的成员 INHERIT FROM 3用于访问曾祖 辈的成员 我们认为应当尽量避免使用INHERIT FROM 2和INHERIT FROM 3宏 因为 这会导致类的继承关系中存在严重的数据耦合 自身类可以直接访问爷爷辈 甚至曾祖父 辈的成员 这将导致程序难于理解 难于维护 因此 在当前版本中 删除了 INHERIT FROM 2和INHERIT FROM 3宏 仅仅保留INHERIT FROM 一般情况下 我 们可以通过更加合理的函数封装 让当前类通过祖先类提供的方法间接地访问祖先类的成 员 如果确实要在当前类中直接访问爷爷辈甚至曾祖辈的成员 我们可以先通过 SUPER PTR 2和SUPER PTR 3将当前对象的指针转型为对应的祖先类指针 然后再通过 其指针访问其成员 写到这里 LW OOPC所有的宏都介绍完毕了 下面 我们介绍LW OOPC对内存泄漏 和调试信息打印的支持 LW OOPC 高级配置高级配置 缺省情况下 LW OOPC 不支持内存泄漏检测 如果需要支持 只要将 define LW OOPC SUPPORT MEMORY LEAK DETECTOR去掉行注释符 define LW OOPC SUPPORT MEMORY LEAK DETECTOR即可 一旦你决定让 LW OOPC 支持内存泄露检测 那么 你必须同时将 lw oopc c 加入工 程 我们再来看看 lw oopc c 中的配置 是否支持调试信息打印 内存分配和释放的详细信息 缺省关闭打印 define LW OOPC PRINT DEBUG INFO 缺省情况下 LW OOPC 不支持调试信息打印 如果需要支持 只要将 define LW OOPC PRINT DEBUG INFO去掉行注释符 define LW OOPC PRINT DEBUG INFO即可 看一个实例 实例工程是 ExprAdvance 可从上下载 第一步 用VC6 VC2005 VC2008打开对应的工程文件 打开lw oopc h 将 LW OOPC SUPPORT MEMORY LEAK DETECTOR的注释打开 如下所示 是否支持内存泄露检测 缺省不支持 define LW OOPC SUPPORT MEMORY LEAK DETECTOR main c的内容 一开始是这样的 include stdio h include Expr h int main Expr expr1 Expr new Expr expr2 Expr new Expr expr3 Expr new Expr expr Expr new expr1 initUnaryX expr1 0 expr2 initUnaryX expr2 5 expr3 initBinaryX expr3 3 4 expr initTernary expr expr1 expr2 expr3 expr print expr printf n Expr delete expr Expr delete expr3 Expr delete expr2 Expr delete expr1 return 0 打开内存泄漏检测的配置项后 重新编译工程 我们发现了一些编译错误 1 c projects expradvance main c 6 error C2198 Expr new 用于调用的参数太少 1 c projects expradvance main c 7 error C2198 Expr new 用于调用的参数太少 1 c projects expradvance main c 8 error C2198 Expr new 用于调用的参数太少 1 c projects expradvance main c 9 error C2198 Expr new 用于调用的参数太少 为了支持内存泄漏的检测 我们需要给每个 构造函数 传入文件名和行号参数 LW OOPC已经为我们准备了一个宏 lw oopc file line 这里 这个宏违反了编程规范 本来宏应该是全部采用大写字母 不过 这里之所以采用小写 是故意希望用户产生一 种错觉 让用户以为lw oopc file line是一个特殊的实参 该实参包含了文件和行号的信息 看看修正编译错误后的代码 include stdio h include Expr h int main Expr expr1 Expr new lw oopc f

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论