您的位置:首页 > 其它

如何用C实现一个类以及些许设计模式

2014-09-22 20:46 483 查看
在一些开源项目中,结构体中有成员变量,成员函数指针,还有结构体,归属上是子结构体,行为上却是父结构体,这就算是没有访问控制的继承和封装。关于多态,可以通过注册函数来覆盖父结构体的方法。构造和析构也可以通过初始化和去初始化函数来实现,注册和反注册也在此进行。

实例程序

parent.h

#ifndef PARENT_H

#include <stdio.h>

struct parent
{
int a;          //成员变量
int (*test)(void);          //成员函数
void (*fly)(void);
void (*display)(const struct parent par_d);
/*......*/
};

void par_init(struct parent *);   //初始化函数

static int par_num;

#endif // PARENT_H


parent.c

#ifndef PARENT_C

#include "parent.h"

static int test(void)
{
return 0;
}

static void fly(void)
{
printf("I can fly\n");
}

static void display(const struct parent par_d)
{
printf("the par->a is %d\nthe par->test is 0x%x\nthe par->fly is 0x%x\n", par_d.a, par_d.test, par_d.fly);
}

void par_init(struct parent *par)   //初始化函数
{
par->a = 1;
par->display = display;     //不必去初始化,方便测试
par->test = test;
par->fly = fly;
}

void par_deinit(struct parent *par)   //去初始化函数
{
par->a = 0;
par->test = NULL;
par->fly = NULL;
}

#endif // PARENT_C


child.h

#ifndef CHILD_H

#include "parent.h"

struct child
{
struct parent parentA;
void (*display)(const struct child cli_d);
};

void A_init(struct child *);

void A_deinit(struct child *);

#endif // CHILD_H


child.c

#ifndef CHILD_C

#include "child.h"

static int CoverMethod[32] = {0};

enum MethodName
{
TEST = 0,
/*......*/
};

#define PRINTNULL(x){ \
if(x) printf("the %s is not NULL\n", #x);      \
else if(!x) printf("the %s is NULL\n", #x);    \
}

static int test(void)
{
return 1;
}

static void display(const struct child cli_d)   //模仿操作法"<<"重载
{
printf("the child is 0x%x\n", &cli_d);
const struct parent par_d = cli_d.parentA;
printf("the parent is 0x%x\n", &par_d);
cli_d.parentA.display(par_d);
}

void A_init(struct child *cli)      //初始化,并注册函数指针
{
par_num++;
par_init(&(cli->parentA));
cli->display = display;       //操作符重载模拟不必去初始化,方便测试
if(NULL != (void *)test)
{
CoverMethod[TEST] = (int)cli->parentA.test;
cli->parentA.test = test;       //覆盖父结构体的方法
}
/*......其他需要覆盖的方法*/
}

void A_deinit(struct child *cli)        //去初始化,反注册
{
if(NULL != (void *)test)
{
cli->parentA.test = CoverMethod[TEST];       //还原父结构体的方法
}
/*......其他需要还原的方法*/

par_num--;
if(!par_num) par_deinit(&(cli->parentA));
}

void main()
{
struct child childA;
A_init(&childA);

const struct child cli_d = childA;
childA.display(cli_d);

printf("the a is %d, the result is %d\n", childA.parentA.a, childA.parentA.test());
childA.parentA.fly();

par_num = 2;        //测试用
A_deinit(&childA);
printf("the a is %d, the result is %d\n", childA.parentA.a, childA.parentA.test());
childA.parentA.fly();

PRINTNULL(childA.parentA.test);
PRINTNULL(childA.parentA.fly);

par_num = 1;        //测试用
A_deinit(&childA);

childA.display(cli_d);

PRINTNULL(childA.parentA.test);
PRINTNULL(childA.parentA.fly);
}

#endif // CHILD_C


以上代码的健壮性很差,只是抛砖引玉,其实函数指针的使用还是比较危险的,需要良好的控制方法

访问控制不太好实现,对于面向过程的C,一般得靠人力进行访问控制的检查;当需要增加统一的功能时,可以直接在父结构体就行修改。注意是在子结构体中包含父结构体

有了类的基础,就可以实现一些设计模式

比如策略模式,可以用两个只有函数指针的父结构体,分别代表独立的不同方法,子结构体初始化的时候可以指向其中一个。

比如单件模式,可以通过精心设计的静态变量和静态方法来实现

当然,对于大部分能使用OO语言的场合,还是使用OO语言。但是在某些特殊的场合,比如Linux内核以及嵌入式编程中,适当引入OO思想对于扩展性还是很有帮助的


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐