用户登录
用户注册

分享至

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

  • 作者: 内涵英雄
  • 来源: 51数据库
  • 2021-09-05

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

软件
前端设计
程序设计
Java相关