您的位置:首页 > 编程语言 > C语言/C++

C语言实现C++多态------函数指针

2016-10-04 16:24 323 查看
序:

前段时间,去复试淘米的面试,被问到了怎么用C语言实现C++中的多态,当时,只是模模糊糊的知道,使用函数指针可以达到C++多态的效果,但是,具体怎么实现,却还是不清楚。最终面试官让我说了一下C++中的多态。虽然知道被挂在了二面,但是,却感觉并没有什么,每一次的失败,都是为了最后一次的成功积蓄力量,回报越晚,回报越大。这不,因为这件事情,我知道了怎么用C语言实现C++的多态。

正文:

1.首先,弄清楚一个问题,C++多态。

(注:摘自C和C++程序员面试秘笈)

多态:同一操作作用于不同对象,可以有不同的解释,产生不同的执行结果。有两种类型的多态性:

<1>编译时的多态性:编译时的多态性是通过重载函数来实现的。对于非虚的成员函数来说,系统在编译时,根据传递的参数、返回的类型等信息决定实现何种操作。

<2>运行时的多态性:运行时的多态性就是指直到系统运行时,才根据实际情况决定实现何种操作。C++中,运行时的多态性通过虚成员实现。

示例:

这里写代码片
#include <iostream>
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++中的多态

(摘自:http://blog.csdn.net/dai_jing/article/details/38232641

这里写代码片
<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 <assert.h>
#include <stdlib.h>
#include <string.h>
#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 <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("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 <assert.h>
#include <stdlib.h>
#include <stdio.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("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 <stdio.h>
#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语言中要想实现多态,函数指针是唯一法宝。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: