C和C++之争由来已久, 可能要持续到它们中的一种去世_. C语言以其简洁明快, 功能强大的特点, 深得开发人员的喜爱, 尤其是在嵌入式开发领域, C语言更是占据了绝对老大的地位. 在我看来, 语言只是工具, 作为程序员, 我们要做的是: 选择合适的语言, 解决恰当的问题. 我们要尊重事实, 考虑开发环境(软硬件环境), 考虑团队成员的水平, 从商用工程的角度讲, 选择团队成员擅长的语言进行开发, 风险要小很多.
一些从Java/C#转到C的程序员们, 无法从面向对象切换到面向过程, 但又必须与C语言同事们在遗留的C系统上开发软件, 他们有时会非常困惑: C语言是面向过程的编程语言, 如何实践面向对象, 甚至面向接口编程呢? 此时, 就非常需要在C语言中实现面向对象的手段, 而LW_OOPC正是应对这一难题的解决之道.
LW_OOPC是什么?
简而言之: LW_OOPC是一套C语言的宏, 总共1个.h文件(如果需要内存泄漏检测支持以及调试打印支持,那么还需要1个.c文件(w_oopc.c,约145行)), 20个宏, 约130行代码. LW_OOPC是一种C语言编程框架, 用于支持在C语言中进行面向对象编程.
LW_OOPC宏介绍
下面, 先通过一个简单的示例来展示LW_OOPC这套宏的使用方法. 我们要创建这样一些对象: 动物(Animal), 鱼(Fish), 狗(Dog), 车子(Car). 显然, 鱼和狗都属于动物, 都会动. 车子也会动, 但是车子不是动物. 会动是这些对象的共同特征, 但是, 显然它们不属于一个家族. 因此, 我们首先考虑抽象出一个接口(IMoveable), 以描述会动这一行为特征:
INTERFACE(IMoveable)
{
void (\*move)(IMoveable\* t); // Move行为
};
INTERFACE宏用于定义接口, 其成员(方法)均是函数指针类型. 然后, 我们分析Animal, 它应该是抽象类还是接口呢? 动物都会吃, 都需要呼吸, 如果仅仅考虑这两个特征, 显然可以把Animal定为接口. 不过, 这里, 为了展示抽象类在LW_OOPC中如何应用. 我们让Animal拥有昵称和年龄属性, 并且, 让动物和我们打招呼(sayHello方法), 但, 我们不允许用户直接创建Animal对象, 所以, 这里把Animal定为抽象类:
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); // 初始化昵称和年龄
};
ABS_CLASS宏用于定义抽象类, 允许有成员属性. 代码的含义参见代码注释. 紧接着, 我们来定义Fish和Dog类, 它们都继承动物, 然后还实现了IMoveable接口:
CLASS(Fish)
{
EXTENDS(Animal); // 继承Animal抽象类
IMPLEMENTS(IMoveable); // 实现IMoveable接口
void (\*init)(Fish\* t, const char\* name, int age); // 初始化昵称和年龄
};
CLASS(Dog)
{
EXTENDS(Animal); // 继承Animal抽象类
IMPLEMENTS(IMoveable); // 实现IMoveable接口
void(\*init)(Dog\* t, const char\* name, int age); // 初始化昵称和年龄
};
为了让Fish对象或Dog对象在创建之后, 能够很方便地初始化昵称和年龄, Fish和Dog类均提供了init方法.下面, 我们来定义Car,车子不是动物, 但可以Move, 因此, 让Car实现IMoveable接口即可:
CLASS(Car)
{
IMPLEMENTS(IMoveable); // 实现IMoveable接口(车子不是动物,但可以Move)
};
接口, 抽象类, 具体类的定义都已经完成了. 下面, 我们开始实现它们. 接口是不需要实现的, 所以IMoveable没有对应的实现代码. Animal是抽象动物接口, 是半成品, 所以需要提供半成品的实现:
/\* 设置动物的昵称\*/
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);
F