转载自:http://www.cnblogs.com/haippy/archive/2012/12/31/2840501.html
上面一篇博客中写了《如何实现 C 的函数重载》,本文将进一步讲讲如何实现 C 语言的继承和多态,其实大致的思想已经在前面的一篇博客《200 行 C 代码实现插件式 NOSQL 存储服务器(一)》中体现过了,主要就是如何灵活运用C的函数指针这一特性!
等等,C本身是不支持继承和多态的,那还煞费苦心实现 C 的继承和多态干嘛呢?其实在 C 的世界里,有一套非常有名的面向对象的框架,用的也非常广,那就是 GObject,它是整个图形界面开发库 GTK 的基石,在IBM developerWorks上有一篇很好的文章介绍 GObject《GObject对象系统》。另外,在 Linux 内核里面也大量使用了面向对象的思想,比如虚拟文件系统,设备驱动等模块,在 lwn 上有两篇文章就讲到了内核中的面向对象,详细请看:《Object oriented design patterns in the kernel, part 1》,《Object oriented design patterns in the kernel, part 2》。
好了,貌似扯远了,现在我们就来动手实现C语言的继承与多态,我们还是以比较经典的动物世界中的实例来举例:假设动物们(包括人)都会吃(Eat),会走(Walk),会说(Talk),而派生类为 dog(汪星人) 和 cat(喵星人),当然还可以是更多,dog 和 cat 都有自己独特的 eat, walk 和 talk 方式,那么大致的代码如下:
基类代码 animal-base.h|c:
/*
* =============================================================================
*
* Filename: animal-base.h
*
* Description: animal base class.
*
* Created: 12/31/2012 11:36:43 AM
*
* Author: Fu Haiping (forhappy), haipingf@gmail.com
* Company: ICT ( Institute Of Computing Technology, CAS )
*
* =============================================================================
*/
#ifndef _ANIMAL_H_
#define _ANIMAL_H_
typedef struct animal_s_ animal_t;
typedef struct animal_ops_s_ animal_ops_t;
/* 动物类,是所有动物类的基类,也是抽象类 */
struct animal_s_ {
char *name; /*< 动物的名称 */
animal_ops_t *animal_ops; /* 动物的基本行为 */
};
/* 动物的基本行为 */
struct animal_ops_s_ {
/* 动物吃了什么食物 */
void (*eat)(char *food);
/* 动物走了多少步 */
void (*walk)(int steps);
/* 动物在说什么 */
void (*talk)(char *msg);
};
/* 基类的构造函数,需要显示调用 */
extern animal_t * animal_init(char *name);
/* 基类的有关操作,如吃,走,说等等 */
extern void animal_eat(animal_t *animal, char *food);
extern void animal_walk(animal_t *animal, int steps);
extern void animal_talk(animal_t *animal, char *msg);
/* 基类的析构函数,需要显示调用 */
extern void animal_die(animal_t *animal);
#endif /* _ANIMAL_H_ */
/*
* =============================================================================
*
* Filename: animal-base.c
*
* Description: animal base class.
*
* Created: 12/31/2012 12:27:27 PM
*
* Author: Fu Haiping (forhappy), haipingf@gmail.com
* Company: ICT ( Institute Of Computing Technology, CAS )
*
* =============================================================================
*/
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "animal-base.h"
/* 基类的构造函数,需要显示调用 */
animal_t * animal_init(char *name)
{
assert(name != NULL);
size_t name_len = strlen(name);
animal_t *animal = (animal_t *)malloc(sizeof(animal_t)
+ sizeof(animal_ops_t) + name_len + 1);
memset(animal, 0, (sizeof(animal_t) + sizeof(animal_ops_t)
+ name_len + 1));
animal->name = (char *)animal + sizeof(animal_t);
memcpy(animal, name, name_len);
animal->animal_ops = (animal_ops_t *)((char *)animal
+ sizeof(animal_t) + name_len + 1);
return animal;
}
/* 基类的有关操作,如吃,走,说等等 */
void animal_eat(animal_t *animal, char *food)
{
animal->animal_ops->eat(food);
return;
}
void animal_walk(animal_t *animal, int steps)
{
animal->animal_ops->walk(steps);
return;
}
void animal_talk(animal_t *animal, char *msg)
{
animal->animal_ops->talk(msg);
return;
}
/* 基类的析构函数,需要显示调用 */
void animal_die(animal_t *animal)
{
assert(animal != NULL);
free(animal);
return;
}
汪星人 dog 类的实现代码:
#include "animal-base.h"
typedef struct dog_s_ dog_t;
struct dog_s_ {
animal_t base; /* 继承自 animal 基类 */
/* 以下还可以添加与 dog 相关的属性和方法(函数指针), 如: */
/* char *owner; // dog 的主人 */
/* void (*hunt)(const char *rabbit); // 猎兔犬 */
};
extern dog_t * dog_init();
extern void dog_die(dog_t * dog);
/*
* =============================================================================
*
* Filename: dog.c
*
* Description: dog class derived from animal base class.
*
* Created: 12/31/2012 12:52:26 PM
*
* Author: Fu Haiping (forhappy), haipingf@gmail.com
* Company: ICT ( Institute Of Computing Technology, CAS )
*
* =============================================================================
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dog.h"
static void eat(char *food);
static void walk(int steps);
static void talk(char *msg);
dog_t * dog_init()
{
dog_t *dog = (dog_t *)malloc(sizeof(dog_t));
animal_t *animal = (animal_t *)animal_init("doggggggggggggg");
memcpy(&(dog->base), animal, sizeof(animal_t));
dog->base.animal_ops->eat = eat;
dog->base.animal_ops->walk = walk;
dog->base.animal_ops->talk = talk;
free(animal);
return dog;
}
void dog_die(dog_t *dog)
{
/* nothing to do here. */
}
static void eat(char *food)
{
printf("I'm a dog, I eat %s\n", food);
}
static void walk(int steps)
{
printf("I'm a dog, I can jump %d steps one time\n", steps);
}
static void talk(char *msg)
{
printf("I'm a dog, I talk my language %s\n", msg);
}
喵星人(cat 类) 的实现代码:
/*
* =============================================================================
*
* Filename: cat.h
*
* Description: cat class derived from animal base class.
*
* Created: 12/31/2012 12:44:05 PM
*
* Author: Fu Haiping (forhappy), haipingf@gmail.com
* Company: ICT ( Institute Of Computing Technology, CAS )
*
* =============================================================================
*/
#include "animal-base.h"
typedef struct cat_s_ cat_t;
struct cat_s_ {
animal_t base; /* 继承自 animal 基类 */
/* 以下还可以添加与 cat 相关的属性和方法(函数指针), 如: */
/* char *owner; // cat 的主人 */
/* void (*hunt)(const char *rabbit); // 猎兔犬 */
};
extern cat_t * cat_init();
extern void cat_die(cat_t * cat);
/*
* =============================================================================
*
* Filename: cat.c
*
* Description: cat class derived from animal base class.
*
* Created: 12/31/2012 12:52:26 PM
*
* Author: Fu Haiping (forhappy), haipingf@gmail.com
* Company: ICT ( Institute Of Computing Technology, CAS )
*
* =============================================================================
*/
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cat.h"
static void eat(char *food);
static void walk(int steps);
static void talk(char *msg);
cat_t * cat_init()
{
cat_t *cat = (cat_t *)malloc(sizeof(cat_t));
animal_t *animal = (animal_t *)animal_init("cat");
memcpy(&(cat->base), animal, sizeof(animal_t));
cat->base.animal_ops->eat = eat;
cat->base.animal_ops->walk = walk;
cat->base.animal_ops->talk = talk;
free(animal);
return cat;
}
void cat_die(cat_t *cat)
{
/* nothing to do here. */
}
static void eat(char *food)
{
printf("I'm a cat, I eat %s\n", food);
}
static void walk(int steps)
{
printf("I'm a cat, I can jump %d steps one time\n", steps);
}
static void talk(char *msg)
{
printf("I'm a cat, I talk my language %s\n", msg);
}
最后,测试代码如下:
/*
* =============================================================================
*
* Filename: main.c
*
* Description: main test.
*
* Created: 12/31/2012 01:00:43 PM
*
* Author: Fu Haiping (forhappy), haipingf@gmail.com
* Company: ICT ( Institute Of Computing Technology, CAS )
*
* =============================================================================
*/
#include <stdio.h>
#include "animal-base.h"
#include "dog.h"
#include "cat.h"
int main(int argc, const char *argv[])
{
dog_t *dog = dog_init();
cat_t *cat = cat_init();
/* dog 类测试 */
animal_eat(dog, "bones");
animal_walk(dog, 5);
animal_talk(dog, "wuang wuang wuang...");
/* cat 类测试 */
animal_eat(cat, "fish");
animal_walk(cat, 3);
animal_talk(cat, "miao miao miao...");
}
当然还有一点点 Makefile 啦:
all:main
main:main.o dog.o cat.o animal-base.o
gcc -o $@ $^
main.o:main.c
cat.o:cat.c
dog.o:dog.c
animal-base.o:animal-base.c
.PHONY:clean
clean:
rm main main.o dog.o cat.o animal-base.o
最后执行结果为:
I'm a dog, I eat bones
I'm a dog, I can jump 5 steps one time
I'm a dog, I talk my language wuang wuang wuang...
I'm a cat, I eat fish
I'm a cat, I can jump 3 steps one time
I'm a cat, I talk my language miao miao miao...
查看完整的代码请移步:https://github.com/forhappy/c-recipes/tree/master/ooc