【C语言开源库】lw_oopc:轻量级的C语言面向对象编程框架

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值