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》。html
c語言裏繼承和多態的實現主要經過函數指針來實現,如今咱們就來動手實現C語言的繼承與多態,咱們以比較經典的動物世界中的實例來舉例:假設動物們(包括人)都會吃(Eat),會走(Walk),會說(Talk),而派生類爲 dog(汪星人) 和 cat(喵星人),固然還能夠是更多,dog 和 cat 都有本身獨特的 eat, walk 和 talk 方式,那麼大體的代碼以下:linux
基類代碼 animal-base.h|c:框架
/* * ============================================================================= * * Filename: animal-base.h * * Description: animal base class. * * * ============================================================================= */ #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. * * ============================================================================= */ #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. * * ============================================================================= */ #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. * * ============================================================================= */ #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. * ============================================================================= */ #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); }
最後,測試代碼以下:spa
/* * ============================================================================= * * Filename: main.c * * Description: main test. * * * ============================================================================= */ #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 :.net
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...