C语言实现C++多态------函数指针
程序员文章站
2022-03-23 19:35:02
序:
前段时间,去复试淘米的面试,被问到了怎么用c语言实现c++中的多态,当时,只是模模糊糊的知道,使用函数指针可以达到c++多态的效果,但是,具体怎么实现,却还是不清楚。最终面试官让我说了一下c+...
序:
前段时间,去复试淘米的面试,被问到了怎么用c语言实现c++中的多态,当时,只是模模糊糊的知道,使用函数指针可以达到c++多态的效果,但是,具体怎么实现,却还是不清楚。最终面试官让我说了一下c++中的多态。虽然知道被挂在了二面,但是,却感觉并没有什么,每一次的失败,都是为了最后一次的成功积蓄力量,回报越晚,回报越大。这不,因为这件事情,我知道了怎么用c语言实现c++的多态。
正文:
1.首先,弄清楚一个问题,c++多态。
(注:摘自c和c++程序员面试秘笈)
多态:同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。有两种类型的多态性:
<1>编译时的多态性:编译时的多态性是通过重载函数来实现的。对于非虚的成员函数来说,在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。
<2>运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。c++中,运行时的多态性通过虚成员实现。
示例:
这里写代码片 #include using namespace std; class a { public: virtual void f() { cout << "a::f()" << endl; } }; class b:public a { public: virtual void f() { cout << "b::f()" << endl; } }; class c:public b { public: void f() { cout << "c::f()" << endl; } }; void test(a &a) //基类的指针或引用 { a.f(); //运行时多态 } int main() { a a; b b; c c; test(a); test(b); test(c); return 0; }
2.c语言实现c++中的多态
这里写代码片 <1>基类头文件 #ifndef _animal_h_ #define _animal_h_ //动物的行为 typedef struct animal_ops_s_ { void (*eat)(char *food); //吃什么食物 void (*walk)(int steps); //走多少步 void (*talk)(char *msg); //说什么 }animal_ops_t; //动物类,所有动物的基类(抽象类) typedef struct animal_s_ { char *name; //动物的名称 animal_ops_t *animal_ops; //动物的行为 }animal_t; //基类的构造函数,需要显示调用 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 <1>基类的实现 #include #include #include #include "animal.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)); memset(animal,0,sizeof(animal)); animal->name = (char *)malloc(name_len + 1); memcpy(animal->name,name,name_len+1); animal->animal_ops = (animal_ops_t *)((char *)animal+name_len + 1); animal->animal_ops->eat = null; animal->animal_ops->walk = null; animal->animal_ops->talk = null; return animal; } //基类相关的操作 void animal_eat(animal_t *animal,char *food) { animal->animal_ops->eat(food); } void animal_walk(animal_t *animal,int steps) { animal->animal_ops->walk(steps); } void animal_talk(animal_t *animal,char *msg) { animal->animal_ops->talk(msg); } //基类的析构函数,需要显示调用 void animal_die(animal_t *animal) { return ; } <2>汪星人头文件 #ifndef _dog_h_ #define _dog_h_ #include "animal.h" typedef struct dog_s_ dog_t; struct dog_s_ { animal_t base; //继承自animal基类 }; extern dog_t *dog_init(); extern void dog_die(dog_t *dog); #endif <2>汪星人实现 #include #include #include #include #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("hello-dog"); 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; animal_die(animal); return dog; } void dog_die(dog_t *dog) { assert(dog != null); free(dog); dog = null; } 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\n",steps); } static void talk(char *msg) { printf("i'm a dog,i talk my language %s\n",msg); } <3>喵星人头文件 #ifndef _cat_h_ #define _cat_h_ #include "animal.h" typedef struct cat_s_ cat_t; struct cat_s_ { animal_t base; //继承自animal基类 }; extern cat_t *cat_init(); extern void cat_die(cat_t *cat); #endif <3>喵星人实现 #include #include #include #include #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("hello-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; return cat; } void cat_die(cat_t *cat) { assert(cat != null); free(cat); cat = null; } 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\n",steps); } static void talk(char *msg) { printf("i'm a cat,i talk my language %s\n",msg); } <4>主函数 #include #include "animal.h" #include "dog.h" #include "cat.h" int main() { cat_t *cat = cat_init(); dog_t *dog = dog_init(); //dog测试 animal_eat(dog,"bones"); animal_walk(dog,5); animal_talk(dog,"wang wang wang..."); //cat测试 animal_eat(cat,"fish"); animal_walk(cat,3); animal_talk(cat,"miao miao miao..."); cat_die(cat); dog_die(dog); return 0;
<5>程序运行结果截图:
3.感悟
实际上,在c语言中,模仿c++实现多态的过程中,对于构造和析构函数都是要显示的进行调用,对于类的成员函数,实际上是通过结构体内部封装的函数指针完成的。而对于从基类继承而来的派生类,它的虚表的确定,实际上是在自身的构造函数中显示的调用基类的构造函数,然后复制基类的构造函数的内容,之后,可以在自己的类中添加一些其他的操作,而对于自己本身的函数成员,在本模块内有效,声明为静态函数,这样就可以避免命名的冲突问题。总之,在c语言中要想实现多态,函数指针是唯一法宝。