C语言多态实现例子

作者:袖梨 2022-06-25


这些设计模式都是基于抽象类的。使用抽象对象是这里的一个核心。

其实我觉得框架化编程的一个核心问题是抽象,用抽象的对象构建程序的主体框架,这是面向对象编程的普遍思想。用抽象构建骨架,再加上多态就形成了一个完整的程序。由于C++语言本身实现了继承和多态,使用这样的编程理念(理念啥意思?跟个风,嘿嘿)在C++中是十分普遍的现象,可以说Virtual(多态)是VC的灵魂。

但是,使用C语言的我们都快把这个多态忘光光了。我常听见前辈说,类?多态?我们用的是C,把这些忘了吧。很不幸的是,我是一个固执的人。这么好的东西,为啥不用呢。很高兴的,在最近的一些纯C代码中,我看见了C中的多态!下面且听我慢慢道来。

1. VC中的Interface是什么

Interface:中文解释是接口,其实它表示的是一个纯虚类。不过我所要说的是,在VC中的Interface其实就是suct,查找Interface的定义,你可以发现有这样的宏定义:

#Ifndef Interface

#define Interface suct

#endif

而且,实际上在VC中,如果一个类有Virtual的函数,则类里面会有v,它实际上是一个虚函数列表。实际上C++是从C发展而来的,它不过是在语言级别上支持了很多新功能,在C语言中,我们也可以使用这样的功能,前提是我们不得不自己实现。

2.C中如何实现纯虚类(我称它为纯虚结构)

比较前面,相信大家已经豁然开朗了。使用suct组合函数指针就可以实现纯虚类。

例子:

typedef suct {

void (*Foo1)();

char (*Foo2)();

char* (*Foo3)(char* st);

}

MyVirtualInterface;

这样假设我们在主体框架中要使用桥模式。(我们的主类是DoMyAct,接口具体实现类是Act1,Act2)下面我将依次介绍这些“类”。(C中的“类”在前面有说明,这里换了一个,是使用早期的数组的办法)

主类DoMyAct: 主类中含有MyVirtualInterface* m_pInterface; 主类有下函数:

DoMyAct_SetInterface(MyVirtualInterface* pInterface)

{

m_pInterface= pInterface;

}

DoMyAct_Do()

{

if(m_pInterface==NULL) return;

m_pInterface->Foo1();

c=m_pInterface->Foo2();

}

子类Act1:实现虚结构,含有MyVirtualInterface st[MAX]; 有以下函数:

MyVirtualInterface* Act1_CreatInterface()

{

index=FindValid() //对象池或者使用Malloc !应该留在外面申请,实例化

if(index==-1) return NULL;

St[index].Foo1=Act1_Foo1; // Act1_Foo1要在下面具体实现

St[index].Foo2=Act1_Foo2;

St[index].Foo3=Act1_Foo3;

Return &st [index];

}

子类Act2同上。

在main中,假设有一个对象List。List中存贮的是MyVirtualInterface指针,则有:

if( (p= Act1_CreatInterface()) != NULL)

List_AddObject(&List, p); //Add All

While(p=List_GetObject()){

DoMyAct_SetInterface(p);//使用Interface代替了原来大篇幅的Switch Case

DoMyAct_Do();//不要理会具体的什么样的动作,just do it

}

FREE ALL

Writer为例,使用宏定义可以如下:

1.TxtWriter.h/.c分别定义和实现txt_writer_open,txt_writer_write,txt_writer_close三个函数,BinWriter.h/.c分别定义和实现bin_writer_open,bin_writer_write,bin_writer_close三个函数;

2.定义头文件Writer.h如下(仅主要部分):

#define  TXT_MODE    1

#define  BIN_MODE    2

#define  WRITER_MODE  TXT_MODE

#if WRITER_MODE==TXTMODE

#include "TxtWriter.h"

#define writer_open  txt_writer_open

#define writer_write  txt_writer_write

#define writer_close  txt_writer_close

#elif WRITER_MODE==BIN_MODE

#include "BinWriter.h"

#define writer_open  bin_writer_open

#define writer_write  bin_writer_write

#define writer_close  bin_writer_close

#endif

从而,在具体使用时引入Writer.h头文件并通过writer_open、writer_write、writer_close调用对应的功能,而改变WRITER_MODE并重新编译,即可实现对应输出模式的切换。

现在我们就来动手实现C语言的继承与多态,我们还是以比较经典的动物世界中的实例来举例:假设动物们(包括人)都会吃(Eat),会走(Walk),会说(Talk),而派生类为 dog(汪星人) 和 cat(喵星人),当然还可以是更多,dog 和 cat 都有自己独特的 eat, walk 和 talk 方式,那么大致的代码如下:

基类代码 animal-base.h|c:


/*
 * =============================================================================
 *
 *       Filename:  animal-base.h
 *
 *    Description:  animal base class.
 *
 *        Created:  12/31/2012 11:36:43 AM
 *
 *         Author:  Fu Haiping (forhappy), [email protected]
 *        Company:  ICT ( Institute Of Computing Technology, CAS )
 *
 * =============================================================================
 */
#ifndef _ANIMAL_H_
#define _ANIMAL_H_

typedef struct animal_s_ animal_t;
typedef struct animal_ops_s_ animal_ops_t;


/* 动物类,是所有动物类的基类,也是抽象类 */
struct animal_s_ {
    char *name; /*< 动物的名称 */
    animal_ops_t *animal_ops; /* 动物的基本行为 */
};

/* 动物的基本行为 */
struct animal_ops_s_ {
    /* 动物吃了什么食物 */
    void (*eat)(char *food);
    /* 动物走了多少步 */
    void (*walk)(int steps);
    /* 动物在说什么 */
    void (*talk)(char *msg);
};

/* 基类的构造函数,需要显示调用 */
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  /* _ANIMAL_H_ */

/*
 * =============================================================================
 *
 *       Filename:  animal-base.c
 *
 *    Description:  animal base class.
 *
 *        Created:  12/31/2012 12:27:27 PM
 *
 *         Author:  Fu Haiping (forhappy), [email protected]
 *        Company:  ICT ( Institute Of Computing Technology, CAS )
 *
 * =============================================================================
 */
#include
#include
#include

#include "animal-base.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)
            + sizeof(animal_ops_t) + name_len + 1);
    memset(animal, 0, (sizeof(animal_t) + sizeof(animal_ops_t)
                + name_len + 1));
    animal->name = (char *)animal + sizeof(animal_t);
    memcpy(animal, name, name_len);
    animal->animal_ops = (animal_ops_t *)((char *)animal
            + sizeof(animal_t) + name_len + 1);

    return animal;
}

/* 基类的有关操作,如吃,走,说等等 */
void animal_eat(animal_t *animal, char *food)
{
    animal->animal_ops->eat(food);
    return;
}

void animal_walk(animal_t *animal, int steps)
{
    animal->animal_ops->walk(steps);
    return;
}

void animal_talk(animal_t *animal, char *msg)
{
    animal->animal_ops->talk(msg);
    return;
}

/* 基类的析构函数,需要显示调用 */
void animal_die(animal_t *animal)
{
    assert(animal != NULL);

    free(animal);
    return;
}
汪星人 dog 类的实现代码:


#include "animal-base.h"

typedef struct dog_s_ dog_t;

struct dog_s_ {
    animal_t base; /* 继承自 animal 基类 */

    /* 以下还可以添加与 dog 相关的属性和方法(函数指针), 如: */
    /* char *owner; // dog 的主人 */
    /* void (*hunt)(const char *rabbit); // 猎兔犬 */
};

extern dog_t * dog_init();
extern void dog_die(dog_t * dog);

/*
 * =============================================================================
 *
 *       Filename:  dog.c
 *
 *    Description:  dog class derived from animal base class.
 *
 *        Created:  12/31/2012 12:52:26 PM
 *
 *         Author:  Fu Haiping (forhappy), [email protected]
 *        Company:  ICT ( Institute Of Computing Technology, CAS )
 *
 * =============================================================================
 */
#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("doggggggggggggg");
    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;

    free(animal);
    return dog;
}

void dog_die(dog_t *dog)
{
    /* nothing to do here. */
}

static void eat(char *food)
{
    printf("I'm a dog, I eat %sn", food);
}

static void walk(int steps)
{
    printf("I'm a dog, I can jump %d steps one timen", steps);
}

static void talk(char *msg)
{
    printf("I'm a dog, I talk my language %sn", msg);
}
喵星人(cat 类) 的实现代码:


/*
 * =============================================================================
 *
 *       Filename:  cat.h
 *
 *    Description:  cat class derived from animal base class.
 *
 *        Created:  12/31/2012 12:44:05 PM
 *
 *         Author:  Fu Haiping (forhappy), [email protected]
 *        Company:  ICT ( Institute Of Computing Technology, CAS )
 *
 * =============================================================================
 */
#include "animal-base.h"

typedef struct cat_s_ cat_t;

struct cat_s_ {
    animal_t base; /* 继承自 animal 基类 */

    /* 以下还可以添加与 cat 相关的属性和方法(函数指针), 如: */
    /* char *owner; // cat 的主人 */
    /* void (*hunt)(const char *rabbit); // 猎兔犬 */
};

extern cat_t * cat_init();
extern void cat_die(cat_t * cat);

/*
 * =============================================================================
 *
 *       Filename:  cat.c
 *
 *    Description:  cat class derived from animal base class.
 *
 *        Created:  12/31/2012 12:52:26 PM
 *
 *         Author:  Fu Haiping (forhappy), [email protected]
 *        Company:  ICT ( Institute Of Computing Technology, CAS )
 *
 * =============================================================================
 */
#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("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;

    free(animal);
    return cat;
}

void cat_die(cat_t *cat)
{
    /* nothing to do here. */
}

static void eat(char *food)
{
    printf("I'm a cat, I eat %sn", food);
}

static void walk(int steps)
{
    printf("I'm a cat, I can jump %d steps one timen", steps);
}

static void talk(char *msg)
{
    printf("I'm a cat, I talk my language %sn", msg);
}
最后,测试代码如下:


/*
 * =============================================================================
 *
 *       Filename:  main.c
 *
 *    Description:  main test.
 *
 *        Created:  12/31/2012 01:00:43 PM
 *
 *         Author:  Fu Haiping (forhappy), [email protected]
 *        Company:  ICT ( Institute Of Computing Technology, CAS )
 *
 * =============================================================================
 */
#include

#include "animal-base.h"
#include "dog.h"
#include "cat.h"

int main(int argc, const char *argv[])
{
    dog_t *dog = dog_init();
    cat_t *cat = cat_init();

    /* dog 类测试 */
    animal_eat(dog, "bones");
    animal_walk(dog, 5);
    animal_talk(dog, "wuang wuang wuang...");

    /* cat 类测试 */
    animal_eat(cat, "fish");
    animal_walk(cat, 3);
    animal_talk(cat, "miao miao miao...");

}
当然还有一点点 Makefile 啦:


all:main

main:main.o dog.o cat.o animal-base.o
    gcc -o $@ $^

main.o:main.c

cat.o:cat.c

dog.o:dog.c

animal-base.o:animal-base.c

.PHONY:clean

clean:
    rm main main.o dog.o cat.o animal-base.o
最后执行结果为:


I'm a dog, I eat bones
I'm a dog, I can jump 5 steps one time
I'm a dog, I talk my language wuang wuang wuang...
I'm a cat, I eat fish
I'm a cat, I can jump 3 steps one time
I'm a cat, I talk my language miao miao miao...

相关文章

精彩推荐