目录
一、概述
在做嵌入式软件开发过程中,当模块越来越多,代码越来越复杂,采用常规的的面向过程方法,容易使得代码混乱。通过合理的运用抽象、封装、继承和多态,更好的组织程序,从而很好地应对这种复杂性。C语言虽然是一门面向过程的语言,但我们知道,面向对象和面向过程是两种编程泛型,是一种解决问题的方法,与语言本身没有关系。不管是C还是C++,都只是一种工具,,有人用C写出大型且牛X的面向对象程序,也有人操着C++这把屠龙刀,却写着面向过程的程序。出于学习的目的,也为了和大家讨论学习,我决定总结自己平时在工作中用到的一些方法,共同探讨一下C在面向对象的一些方法以及设计模式。
二、C++在类上的实现
我们来看一个简单的C++类:
class Person{
public:
void getName(){
printf("%s\n",name);
}
void setName();
private:
char name[20];
int age;
};
在分配内存之后,实际上对象只分配了数据成员的存储空间。因此实际上在内存分配上,其实类与结构体是相同的,即在内存分配上与下面这个结构体相同。
struct Person{
char name[20];
int age;
}
C++相同类的所有对象实际上都共用相同的代码段,有人会问,既然所有对象都调用相同的函数,那在调用成员函数时候,计算机是怎么选择去操作哪个对象的数据成员呢?可能学过C++的人都听说过this指针,虽然不一定知道它是个啥。
2.1 什么是this 指针?
C++每创建一个对象时候,会将该对象的起始地址赋值给this指针。例如之前的例子,类Person在编译完之后,其实getName编译成了:
void getName(* this){
printf("%s\n",this->name);
}
如此可见,其实用C就可以写出面向对象的程序,只不过是没有C++那般方便,需要绕一些弯路,我们可以模仿this指针来实现。
2.2 面向对象的三大特性
三大特性:封装、继承、多态
我们知道很多设计模式都基于这三大特性来实现的,接下来我来简单介绍如何用C语言来实现这三大特性
三、用C实现面向对象的三大特性
3.1 封装
类有数据成员和成员函数,即数据与方法,在C语言中,我们可以配合结构体以及函数指针来实现,简单实现如下:(这里主要是讲思想,如果已经理解思想,而更追求结果,可直接跳转到:点击这里)
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct Person Person;
struct Person{
void (*whoIam)(Person *this);
void (*setName)(Person *this,char * name);
char name[20];
int age;
};
void whoIam(Person *this){
printf("I am a %s\n",this->name);
}
void setName(Person *this, char * name){
strcpy(this->name, name);
}
void init(Person* obj){
obj->setName = setName;
obj->whoIam = whoIam;
}
int main(){
Person* man,*girl;
//实例化对象
man = (Person*)malloc(sizeof(Person));
girl = (Person*)malloc(sizeof(Person));
init(man);
init(girl);
//成员函数的调用
man->setName(man,"man");
girl->setName(girl,"girl");
man->whoIam(man);
girl->whoIam(girl);
return 0;
}
从上面的代码来看,结构体person类似于C++的类,封装了成员函数whoIam和setName,有数据成员name 和age;这里着重介绍C面向对象的思想,关于更好的封装,请看后续的的教程。
3.2 继承
废话不多说,直入代码:
typedef struct Girl Girl;
struct Girl{
Person father;
void (*buildChild)(Girl *this);
};
void buildChild(){
printf("I can build a baby\n");
}
void Girl_init(Girl* obj){
//构造基类
init(&(obj->father));
obj->buildChild = buildChild;
}
int main(){
Girl* girl;
//实例化对象
girl = (Girl*)malloc(sizeof(Girl));
Girl_init(girl);
//调用父类方法
girl->father.setName(girl,"xiaohong");
girl->father.whoIam(girl);
//调用子类新方法
girl->buildChild(girl);
return 0;
}
继承可直接在新类,结构体内定义父类的一个成员,如上程序,由程序可见,新类Girl 继承Person,拥有了Person的属性和方法,同时又增加了自己新的能力,buildChild,即女孩是人的一种,但她会造小孩,这是她新的能力。
3.3 多态
上面介绍了封装、继承,下面说说多态。直接上程序:
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct Person Person;
//人类
struct Person{
void (*whoIam)(Person *this);
void (*setName)(Person *this,char * name);
void (*buildChild)(Person *this);
char name[20];
int age;
};
void whoIam(Person *this){
printf("I am %s\n",this->name);
}
void setName(Person *this, char * name){
strcpy(this->name, name);
}
void init(Person* obj){
obj->setName = setName;
obj->whoIam = whoIam;
}
//女人类
typedef struct Girl Girl;
struct Girl{
Person father;
void (*buildChild)(Girl *this);
};
void Girl_buildChild(){
printf("I can build a baby one month\n");
}
void Girl_init(Girl* obj){
//构造基类
init(&(obj->father));
obj->buildChild = Girl_buildChild;
obj->father.buildChild = obj->buildChild;
}
//男人类
typedef struct Man Man;
struct Man{
Person father;
void (*buildChild)(Man *this);
};
void man_buildChild(){
printf("I can build tens of thousands of baby every day\n");
}
void Man_init(Man* obj){
//构造基类
init(&(obj->father));
obj->buildChild = man_buildChild;
obj->father.buildChild = obj->buildChild;
}
int main(){
Person* zhang;
//实例化为男人
zhang = (Man*)malloc(sizeof(Man));
Man_init(zhang);
zhang->buildChild(zhang);
//实例化为女人
zhang = (Girl*)malloc(sizeof(Girl));
Girl_init(zhang);
zhang->buildChild(zhang);
return 0;
}
上面是完整代码,运行结果如下:
I can build tens of thousands of baby every day
I can build a baby one month
首先“人”类都拥有造孩子的能力,所以“男人”和“女人”类都继承于人,所以都会造小孩,但是“男”和“女”各自造小孩的能力有有所差异,在主函数中,我们定义一个基类指针“小张同学”,小张同学原本是个男人,但后来做了变性手术,科技太强大,就连生孩子的能力也变了。以上即用C实现了类似于C++的虚函数特性,多态中的一种。
四、总结
以上介绍了用C实现面向对象编程的思想,下篇我将介绍一种封装的比较好的C面向对象开发库的运用。如果本文对你理解面向对象编程思想有点作用,别忘了点个赞哟......