欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

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;
    }

C语言实现C++多态------函数指针
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>程序运行结果截图:
C语言实现C++多态------函数指针
3.感悟
实际上,在c语言中,模仿c++实现多态的过程中,对于构造和析构函数都是要显示的进行调用,对于类的成员函数,实际上是通过结构体内部封装的函数指针完成的。而对于从基类继承而来的派生类,它的虚表的确定,实际上是在自身的构造函数中显示的调用基类的构造函数,然后复制基类的构造函数的内容,之后,可以在自己的类中添加一些其他的操作,而对于自己本身的函数成员,在本模块内有效,声明为静态函数,这样就可以避免命名的冲突问题。总之,在c语言中要想实现多态,函数指针是唯一法宝。