使用C语言实现面向对象程序设计
学过c语言的人都直到c语言学习语法简单,但精通起来比较难,难点在于c语言太“低级”,它面向的是机器的一个执行过程,不像C++、java这种高级语言,在语法层级就支持面向对象的抽象。所以往往初学者在使用c语言编程时,稍微遇到复杂一点的功能,就会出现各种全局变量,标志位满天飞的情况,代码维护性和阅读性变得很差,过个一两年再去阅读自己以前写的代码,遇到没写注释的全局变量,可能都得靠猜。
但其实这也是c语言区别于其他语言最优秀的地方,因为语法简单,没有语法上的各种约束和限制,它是最容易上手的语言,其他面向对象的语言,你首先得有一个对事物的抽象能力,才能把程序的结构设计好。同时它具有别的编程语言不能比拟的最优秀的执行效率,因此在资源受限的场景下,比如嵌入式,单片机等,c语言是一个不错的选择。但并不意味着c语言只能处理这种偏“底层”的应用场景,使用c语言同样能实现面向对象的程序设计。并且它在某些方面还优于其他高级语言。下面结合我的理解讲一讲如何使用c语言实现面向对象的程序设计。
面向对象核心特性
1. 封装
通过结构体与函数指针捆绑数据与操作,例如封装一个对象,用于描述系统电源特性,包括电压、电流、充放电状态等,同时定义这个对象的操作方法
电源 {
电压,
电流,
电源状态,
剩余电量,
操作方法:
获取电压;
获取电流;
获取电源状态;
获取剩余电量;
设置电源状态;
}
那么使用c语言如何来实现呢?
我们可以在结构体中定义对象的属性,然后使用函数指针定义这个对象的操作方法,如下:
power.h头文件定义如下:
#ifndef POWER_H #define POWER_H #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #define GET_POWER(obj) ((Power *)obj) // 类声明 typedef struct _Power Power; typedef struct _PowerFun PowerFun; // 类成员函数结构 struct _PowerFun { void (*destroy)(Power* self); uint16_t (*getVoltage)(Power* self);//获取电压; uint16_t (*getCurrent)(Power* self);//获取电流; uint16_t (*getPowerState)(Power* self);//获取电源状态; uint16_t (*getPowerLevel)(Power* self);//获取剩余电量; void (*setPowerState)(Power* self, uint8_t state);//设置电源状态; }; // 类结构 struct _Power { const PowerFun* fun; // TODO: 添加数据成员 uint16_t voltage; //电压, uint16_t current; //电流, uint16_t power_state;//电源状态, uint16_t power_level;//剩余电量, }; // 构造函数声明 Power* power_create(); void power_init(Power* self); // 析构函数声明 void power_deinit(Power* self); #endif // POWER_Hpower.c具体实现如下:
#include "power.h" #include <stdio.h> static uint16_t power_getCurrent(Power* self); static uint16_t power_getPowerState(Power* self); static uint16_t power_getPowerLevel(Power* self); static void power_setPowerState(Power* self, uint8_t state); static uint16_t power_getVoltage(Power* self); // 析构函数声明 static void power_destroy(Power* self); // TODO: 初始化数据成员 static const PowerFun power_fun = { .destroy = power_destroy, .getVoltage = power_getVoltage, .getCurrent = power_getCurrent, .getPowerState = power_getPowerState, .getPowerLevel = power_getPowerLevel, .setPowerState = power_setPowerState, }; // 构造函数实现 Power* power_create() { Power* obj = (Power*)malloc(sizeof(Power)); if (obj) { memset(obj, 0, sizeof(Power)); power_init(obj); } return obj; } void power_init(Power* self) { self->fun = &(power_fun); // TODO: 初始化数据成员 } void power_deinit(Power* self) { // TODO: 数据成员申请资源释放 } // 析构函数实现 static void power_destroy(Power* self) { if (self != NULL) { power_deinit(self); free(self); } } // getVoltage method static uint16_t power_getVoltage(Power* self) { if (self != NULL) { return self->voltage; } return 0; } // getCurrent method static uint16_t power_getCurrent(Power* self) { if (self != NULL) { return self->current; } return 0; } // getPowerState method static uint16_t power_getPowerState(Power* self) { if (self != NULL) { return self->power_state; } return 0; } // getPowerLevel method static uint16_t power_getPowerLevel(Power* self) { if (self != NULL) { return self->power_level; } return 0; } // setPowerState method static void power_setPowerState(Power* self, uint8_t state) { if (self != NULL) { self->power_state = state; } }使用方法很简单
Power* systempower = power_create(); systempower->fun->getVoltage(systempower);//获取电压; systempower->fun->getCurrent(systempower);//获取电流; systempower->fun->getPowerState(systempower);//获取电源状态; systempower->fun->getPowerLevel(systempower);//获取剩余电量; systempower->fun->setPowerState(systempower, 11);//设置电源状态;2. 继承
所谓继承,就是基于一个已有的类(父类)来创建一个新的类(子类)。子类会自动获得父类的属性和方法,并且可以在此基础上进行扩展,增加自己特有的属性和方法,或者修改父类的方法。
那么在c语言中如何实现继承呢?我们可以通过结构体嵌套实现这种继承的层次关系
回到上面的例子,再次定义一个对象chargepower继承自上面定义的power对象,这个对象新增充电和放电操作方法,并且新增了充电电流、电压和放电电流、电压、充满剩余时间等属性。
充放电电源:继承电源 {
充电电压,
充电电流,
放电电压,
放电电流,
充满剩余时间,
操作方法:
充电;
放电;
}
chargepower.h定义如下
#ifndef CHARGEPOWER_H #define CHARGEPOWER_H #include <stdint.h> #include <stdbool.h> #include "Power.h" #define GET_CHARGEPOWER_VTABLE(obj) GET_POWER_VTABLE(obj) //(*(ChargepowerVTable **)obj) #define GET_CHARGEPOWER(obj) ((Chargepower *)obj) // 派生类声明 typedef struct _Chargepower Chargepower; typedef struct _ChargepowerFun ChargepowerFun; // 类成员函数结构 struct _ChargepowerFun { void (*destroy)(Chargepower* self); void (*charge)(Chargepower* self);//充电 void (*discharge)(Chargepower* self);//放电 }; struct _Chargepower { Power base; // 基类作为第一个成员 const ChargepowerFun* fun; // TODO: 添加派生类特有的数据成员 uint16_t charge_voltage; //充电电压, uint16_t charge_current; //充电电流, uint16_t discharge_voltage;//放电电压, uint16_t discharge_current;//放电电流, uint16_t charge_time;//充电剩余时间 }; // 构造函数声明 Chargepower* chargepower_create(); void chargepower_init(Chargepower* self); // 析构函数声明 void chargepower_deinit(Chargepower* self); #endif // CHARGEPOWER_Hchargepower.c定义如下:
#include "chargepower.h" #include <stdio.h> #include <stdlib.h> static void chargepower_discharge(Chargepower* self); static void chargepower_charge(Chargepower* self); // 析构函数声明 static void chargepower_destroy(Chargepower* self); // TODO: 初始化数据成员 static const ChargepowerFun chargepower_fun = { .destroy = chargepower_destroy, .charge = chargepower_charge, .discharge = chargepower_discharge, }; // 构造函数实现 Chargepower* chargepower_create() { Chargepower* obj = (Chargepower*)malloc(sizeof(Chargepower)); if (obj) { memset(obj, 0, sizeof(Chargepower)); chargepower_init(obj); } return obj; } void chargepower_init(Chargepower* self) { // 初始化基类部分 power_init(&self->base); self->fun = &(chargepower_fun); // TODO: 初始化派生类特有成员 } void chargepower_deinit(Chargepower* self) { power_deinit(GET_POWER(self)); // TODO: 数据成员申请资源释放 } // 析构函数实现 static void chargepower_destroy(Chargepower* self) { if (self != NULL) { chargepower_deinit(self); free(self); } } // charge method static void chargepower_charge(Chargepower* self) { // TODO: add charge method } // discharge method static void chargepower_discharge(Chargepower* self) { // TODO: add discharge method }如何使用chargepower对象中的父类和自身的方法呢?
使用下面的方式即可:
Chargepower *chargepower = chargepower_create(); //调用自身方法 chargepower->fun->charge(chargepower); //充电 chargepower->fun->discharge(chargepower);//放电 //调用父类方法 GET_POWER(chargepower)->fun->getVoltage(GET_POWER(chargepower));//获取电压; GET_POWER(chargepower)->fun->getCurrent(GET_POWER(chargepower));//获取电流; GET_POWER(chargepower)->fun->getPowerState(GET_POWER(chargepower));//获取电源状态; GET_POWER(chargepower)->fun->getPowerLevel(GET_POWER(chargepower));//获取剩余电量; GET_POWER(chargepower)->fun->setPowerState(GET_POWER(chargepower), 12);//设置电源状态;3. 多态
多态的字面意思是"多种形态"。在面向对象编程中,它指的是:同一个行为(方法)在不同的对象上会表现出不同的实现方式。
简单来说就是:使用统一的接口来操作不同类型的对象,而这些对象会根据自己的特性做出不同的响应。
那么在c语言中如何来实现多态呢?
我们可以利用函数指针,动态绑定不同的操作函数来实现多态,例如,可以在定义对象的时候,定义一个虚函数表这个虚函数表指针可以由继承的对象赋值,不同的继承对象可以赋值不同操作函数,从而实现多态
虚函数表{
虚函数指针;
}
电源 {
虚函数表,
电压,
电流,
电源状态,
剩余电量,
操作方法:
获取电压;
获取电流;
获取电源状态;
获取剩余电量;
设置电源状态;
}
示例代码,定义virtualpower.h如下:
#ifndef VIRTUALPOWER_H #define VIRTUALPOWER_H #include <stdlib.h> #include <stdint.h> #include <stdbool.h> #include <string.h> #define GET_VIRTUALPOWER_VTABLE(obj) (*(VirtualpowerVTable **)obj) #define getMaxCurrent_override(func_name) static uint16_t func_name(Virtualpower* self) #define def_getMaxCurrent(obj) (GET_VIRTUALPOWER_VTABLE(obj)->getMaxCurrent) #define virtual_getMaxCurrent(obj, ...) def_getMaxCurrent(obj)(obj, ##__VA_ARGS__) #define GET_VIRTUALPOWER(obj) ((Virtualpower *)obj) // 类声明 typedef struct _Virtualpower Virtualpower; typedef struct _VirtualpowerFun VirtualpowerFun; typedef struct _VirtualpowerVTable VirtualpowerVTable; // 虚函数表结构 typedef struct _VirtualpowerVTable { // TODO : 添加其他虚函数 uint16_t (*getMaxCurrent)(Virtualpower* self);//虚函数,由继承类来实现定义 }; // 类成员函数结构 struct _VirtualpowerFun { void (*destroy)(Virtualpower* self); uint16_t (*getVoltage)(Virtualpower* self); uint16_t (*getCurrent)(Virtualpower* self); uint16_t (*getPowerState)(Virtualpower* self); uint16_t (*getPowerLevel)(Virtualpower* self); void (*setPowerState)(Virtualpower* self, uint8_t state); }; // 类结构 struct _Virtualpower { VirtualpowerVTable* vtable; const VirtualpowerFun* fun; // TODO: 添加数据成员 uint16_t voltage; //电压, uint16_t current; //电流, uint16_t power_state;//电源状态, uint16_t power_level;//剩余电量, }; // 构造函数声明 Virtualpower* virtualpower_create(); void virtualpower_init(Virtualpower* self); // 析构函数声明 void virtualpower_deinit(Virtualpower* self); #endif // VIRTUALPOWER_H定义virtualpower.c如下:
#include "virtualpower.h" #include <stdio.h> static uint16_t virtualpower_getVoltage(Virtualpower* self); static uint16_t virtualpower_getCurrent(Virtualpower* self); static uint16_t virtualpower_getPowerState(Virtualpower* self); static uint16_t virtualpower_getPowerLevel(Virtualpower* self); static void virtualpower_setPowerState(Virtualpower* self, uint8_t state); // 析构函数声明 static void virtualpower_destroy(Virtualpower* self); // TODO: 初始化数据成员 static const VirtualpowerFun virtualpower_fun = { .destroy = virtualpower_destroy, .getVoltage = virtualpower_getVoltage, .getCurrent = virtualpower_getCurrent, .getPowerState = virtualpower_getPowerState, .getPowerLevel = virtualpower_getPowerLevel, .setPowerState = virtualpower_setPowerState, }; // 构造函数实现 Virtualpower* virtualpower_create() { Virtualpower* obj = (Virtualpower*)malloc(sizeof(Virtualpower)); if (obj) { memset(obj, 0, sizeof(Virtualpower)); virtualpower_init(obj); } return obj; } void virtualpower_init(Virtualpower* self) { if (self->vtable == NULL) { self->vtable = (VirtualpowerVTable *) malloc(sizeof(VirtualpowerVTable)); memset(self->vtable , 0, sizeof(VirtualpowerVTable)); } self->fun = &(virtualpower_fun); // TODO: 初始化数据成员 } void virtualpower_deinit(Virtualpower* self) { if (self->vtable != NULL) { free(self->vtable); self->vtable = NULL; } // TODO: 数据成员申请资源释放 } // 析构函数实现 static void virtualpower_destroy(Virtualpower* self) { if (self != NULL) { virtualpower_deinit(self); free(self); } } // getVoltage method static uint16_t virtualpower_getVoltage(Virtualpower* self) { // TODO: add getVoltage method return 0; } // getCurrent method static uint16_t virtualpower_getCurrent(Virtualpower* self) { // TODO: add getCurrent method return 0; } // getPowerState method static uint16_t virtualpower_getPowerState(Virtualpower* self) { // TODO: add getPowerState method return 0; } // getPowerLevel method static uint16_t virtualpower_getPowerLevel(Virtualpower* self) { // TODO: add getPowerLevel method return 0; } // setPowerState method static void virtualpower_setPowerState(Virtualpower* self, uint8_t state) { // TODO: add setPowerState method }那么当有子类继承Virtualpower这个父类时,可以实现这个虚函数
GET_VIRTUALPOWER_VTABLE(obj)->getMaxCurrent = xxxx
例如定义sonpower子类,继承自virtualpower
sonpower.h实现
#ifndef SONPOWER_H #define SONPOWER_H #include <stdint.h> #include <stdbool.h> #include "Virtualpower.h" #define GET_SONPOWER_VTABLE(obj) GET_VIRTUALPOWER_VTABLE(obj) //(*(SonpowerVTable **)obj) #define GET_SONPOWER(obj) ((Sonpower *)obj) // 派生类声明 typedef struct _Sonpower Sonpower; typedef struct _SonpowerFun SonpowerFun; // 类成员函数结构 struct _SonpowerFun { void (*destroy)(Sonpower* self); }; struct _Sonpower { Virtualpower base; // 基类作为第一个成员 const SonpowerFun* fun; // TODO: 添加派生类特有的数据成员 }; // 构造函数声明 Sonpower* sonpower_create(); void sonpower_init(Sonpower* self); // 析构函数声明 void sonpower_deinit(Sonpower* self); #endif // SONPOWER_Hsonpower.c实现
#include "sonpower.h" #include <stdio.h> #include <stdlib.h> getMaxCurrent_override(sonpower_getMaxCurrent_impl); // 析构函数声明 static void sonpower_destroy(Sonpower* self); // TODO: 初始化数据成员 static const SonpowerFun sonpower_fun = { .destroy = sonpower_destroy, }; // 构造函数实现 Sonpower* sonpower_create() { Sonpower* obj = (Sonpower*)malloc(sizeof(Sonpower)); if (obj) { memset(obj, 0, sizeof(Sonpower)); sonpower_init(obj); } return obj; } void sonpower_init(Sonpower* self) { // 初始化基类部分 virtualpower_init(&self->base); self->fun = &(sonpower_fun); // TODO: 初始化派生类特有成员 def_getMaxCurrent(self) = sonpower_getMaxCurrent_impl; } void sonpower_deinit(Sonpower* self) { virtualpower_deinit(GET_VIRTUALPOWER(self)); // TODO: 数据成员申请资源释放 } // 析构函数实现 static void sonpower_destroy(Sonpower* self) { if (self != NULL) { sonpower_deinit(self); free(self); } } // getMaxCurrent method getMaxCurrent_override(sonpower_getMaxCurrent_impl) { // TODO: add getMaxCurrent method Sonpower *sonpower = (Sonpower *)self; //params return 0; }如何使用这个虚函数呢?
也很简单
Sonpower *sonpower = sonpower_create(); uint16_t maxcurrent = virtual_getMaxCurrent(GET_VIRTUALPOWER(systempower));通过上面给出的例子,可以实现在c语言下使用面向对象编程。但是看起来代码比较繁杂,很多代码看起来都是一样的模式,能不能做一个插件呢?将这些重复的地方通过插件直接自动生成了,这样就不需要一行行手敲了,当然可以,下次再聊!
如果使用vscode开发,有便利工具插件
VSCode面向对象c插件开源实现