文章目录
- 简述OOPC
- 开发环境
- 知识讲解
- 函数示例
- 类的实现示例
- 接口实现示例
(前面两部分有点无聊,如果大家没兴趣看可以直接从知识讲解开始看)
简述OOPC
oopc,是一种轻量级的面向对象的C语言编程框架, LW_OOPC是Light-Weight Object-Oriented Programming in(with) C的缩写,总共一个.h文件, 20个宏, 约130行代码, 非常的轻量级, 但却很好的支持了很多面向对象的特性, 比如继承, 多态。 可以优美的实现面向接口编程。 这个框架是由台湾的高焕堂先生以及他的MISOO团队首创。
开发环境
- 采用vscode为IDE
- 使用makefile编写编译规则
- 使用GCC编译器
这里vscode的作用主要是编辑,哈哈哈。至于使用makefile编写编译规则,它既可以减少不必要的编译次数(文件数量较少体现不出),也解决了博主在vscode的同一个项目中,无法同时编译多个.c文件,总之,非常好用。😅🤣
知识讲解
面向对象语言开发特性:
- 封装:根据职责将属性和方法封装到一个抽象的类中;
- 继承:实现代码的重用,相同的代码不需要重复的写;
- 多态:以封装和继承为前提,不同的子类对象调用相同的方法,产生不同的执行结果;
函数指针
指针,形象化地来说就是一个指向一个空间的地址,也就是通过这个指针可以访问这个地址存储的内容。
函数指针,是一个函数经过编译后,计算机会给它分配一段存储空间,而函数指针实际上是指向这段存储空间首地址的一个指针。 那么其函数名就表示函数的指针,代表了函数的起始地址。
函数指针格式为 类型名 (*指针变量名) (函数参数列表)
,这里的类型名也可以理解为函数返回值的类型。
例如:
- 一个不带参数的函数指针可以表示为:
void (*pFun) (void)
;- 一个带1个参数的函数指针可以表示为:
void (*pFun) (int)
;- 一个带1个参数并且有返回值的函数指针可以表示为:
int (*pFun) (int)
;
当需要指向一个函数时,需要定义一个返回值、函数参数个数类型一致的函数,例如:
#include "stdio.h"
void fun(void)
{
printf("this is fun\n");
}
int main(void)
{
void (*p) (void);
p = fun;
(*p)();
return 0;
}
其运行结果为:
那么一起来看看oopc是如何是如何进行面向对象开发的吧!🤤🤤🤤
关键字CLASS
oopc中,一个类实际上是通过一个结构体实现。伪关键字CLASS
实际上是通过define
重新声明得到,实际上其定义为#define CLASS(type) typedef struct type type
。(将其称为伪关键字是因为:在面向对语言中其确实是一个关键字,如java、python等确实有关键字class,而oopc的CLASS是通过声明得到,并不是C语言实际存在的关键字。)
例如,定义一个类A:
// 类
CLASS (A)
{
···// 属性及方法
};
关键字IMPLEMENTS
implements
关键字,在面向对象语言中,是继承一个接口比不可少的关键字(这里指java语言)。其实在基于oopc的C语言开发中,也是类似的。
在oopc中,关键字IMPLEMENTS
本质也是一个结构体,只不过就是将一个结构体变量名重新声明成IMPLEMENTS
了,其声明为#define IMPLEMENTS(type) struct type type
。(IMPLEMENTS也是一个伪关键字)
明白了类的实现,接口的实现也就简单了,因为两者的本质都是结构体嘛。其实现为:
// 接口
INTERFACE (base)
{
···// 接口的属性及方法
};
构造器CTOR
在oopc中,构造器CTOR
是一个非常重要的玩意。
在oopc程序中,设计类是一件重要的工作,其目的是借之产生对象。“构造器”(Constructor)函数,可称之为“对象之母”,它能够依照类的定义产生对象。
构造器CTOR
在lw_oopc.h文件中的声明为:
#define CTOR(type) \
type* type##_new() { \
struct type *cthis; \
cthis = (struct type*)malloc(sizeof(struct type)); \
if(!cthis) \
{ \
return 0; \
} \
type##_ctor(cthis); \
return cthis; \
}
不难看出:CTOR
构造器的主要功能为,使用malloc函数分配内存空间给所声明的对象。
使用示例:
在头文件中使用
// 类的声明
class (A)
{
void (*fun) (void);
}
// 外部声明
extern A* A_new();
在.c文件中使用
// 类的方法
static void testFun(void)
{
printf("this is a fun");
}
// 使用构造器构造类
CTOR (A)
FUNCTION_SETTING(fun,testFun);
END_CTOR
在这里需要注意:外部声明函数extern A* A_new();声明时一定要使用类的名字,否则会出现报错。(这个声明可加可不加,网上也有很多帖子是使用ANew()来声明一个类的,可能是其修改了lw_oopc.h文件中的声明吧。)
函数示例
类的实现示例
main.c文件
#include <stdio.h>
#include "light.h"
#include "lw_oopc.h"
void main(void)
{
printf("class light test\n");
Light*n = (Light*)Light_new();
n->init(n);
printf("light state:%d\n",n->getState(n));
n->setState(n,1);
printf("new light state:%d\n",n->getState(n));
}
light.c文件
#include "light.h"
#include "stdio.h"
#include "lw_oopc.h"
// 灯类的初始化
static void lightInit(void *light)
{
Light*pthis = (Light*)light;
pthis->state = 0;
}
// 获取灯的状态
static int getLightState(void *light)
{
Light*pthis = (Light*)light;
return pthis->state;
}
// 设置灯的状态
static void setLightState(void *light,int newState)
{
Light*pthis = (Light*)light;
pthis->state = newState;
}
// 构造器 分配空间给类
CTOR (Light)
FUNCTION_SETTING(init,lightInit);
FUNCTION_SETTING(getState,getLightState);
FUNCTION_SETTING(setState,setLightState);
END_CTOR
light.h文件
#ifndef _LIGHT_H
#define _LIGHT_H
#include "lw_oopc.h"
CLASS (Light)
{
int state;
void (*init) (void*);
int (*getState) (void*);
void (*setState) (void*,int newState);
};
// 相当于重新new一个灯类
extern Light* Light_new();
#endif // _DATA_H
vscode运行结果
接口实现示例
main.c文件
#include <stdio.h>
#include "lw_oopc.h"
#include "myInterface.h"
// 接口测试
void main(void)
{
// 圆类的实现
circle*c = (circle*)circle_new();
c->baseShape.init(c,"circle");
c->baseShape.draw(c);
c->vMove(c);
// 正方形类的实现
square* s = square_new();
s->baseShape.init(s,"square1");
s->baseShape.draw(s);
s->vMove(s);
}
myInterface.h文件
#ifndef _MYINTERFACE_H
#define _MYINTERFACE_H
#include "lw_oopc.h"
// 接口
INTERFACE (baseShape)
{
char name[10];
void (*init) (void*,char*);
void (*draw) (void*);
};
// 圆类
CLASS (circle)
{
IMPLEMENTS (baseShape);
void (*vMove) (void*);
};
extern circle* circle_new();
// 正方形类
CLASS (square)
{
IMPLEMENTS (baseShape);
void (*vMove) (void*);
};
extern square* square_new();
#endif //_MYINTERFACE_H
myInterface.c文件
#include "myInterface.h"
#include "string.h"
#include "stdio.h"
/********************圆类的实现*******************/
void cinit(void*p,char*name)
{
circle*pthis = (circle*)p;
strcpy(pthis->baseShape.name,name);
}
void cdraw(void*p)
{
circle*pthis = (circle*)p;
printf("%s drawing\n",pthis->baseShape.name);
}
void cmove(void *p)
{
circle*pthis = (circle*)p;
printf("%s moving\n",pthis->baseShape.name);
}
CTOR (circle)
FUNCTION_SETTING(vMove,cmove);
FUNCTION_SETTING(baseShape.init,cinit);
FUNCTION_SETTING(baseShape.draw,cdraw);
END_CTOR
/********************正方形类的实现*******************/
void sinit(void*p,char*name)
{
square*pthis = (square*)p;
strcpy(pthis->baseShape.name,name);
}
void sdraw(void*p)
{
square*pthis = (square*)p;
printf("%s drawing\n",pthis->baseShape.name);
}
void smove(void *p)
{
square*pthis = (square*)p;
printf("%s moving\n",pthis->baseShape.name);
}
CTOR (square)
FUNCTION_SETTING(vMove,smove);
FUNCTION_SETTING(baseShape.init,sinit);
FUNCTION_SETTING(baseShape.draw,sdraw);
END_CTOR
结果
lw_oopc相关的文件大家可以去gitee或者是github上面找找,上面有很多示例,博主还没完全码明白。oopc相关文件的示例仓库😅😅😅
小编会持续更新的哟!欢迎大家点赞+收藏+关注!!!🤤🤤🤤