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

序:
前段时间,去复试淘米的面试,被问到了怎么用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语言中要想实现多态,函数指针是唯一法宝。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值