继承是为了实现多态,即可以把子类当父类来用。
我们一般在父类中声明接口,在子类中实现接口。所谓接口,就是一个个函数组成的集合。
以上观点,不喜勿喷。
下面言归正传
思路:
用C实现继承很简单,子结构体内包含父结构体成员就可以了,把子类当父类来使用时只需要一次强制类型转换。
那么实现多重继承呢?
思路也很简单,一点就破。
沿用单继承的实现思路,我们还是像之前实现单继承那样子结构体内包含多个父结构体的所有成员,发现当作父类使用时无法像之前那样方便地利用C语言提供的强制类型转换。原因是什么?
无法将所有的父都放在结构体的开头,因为一个结构体只有一个开头,哈哈。
我们最终的目的是什么?
我们最终的目的是获取子结构体里存在的父的特性。
相比与第一个父,第二个、第三个父无非就是多了个偏移,知道了这个偏移自然就拿到了从属于父的数据。
问题就变成了怎么获取偏移,或怎么获取数据,核心其实是获取数据。
我这里用的一种方法会浪费一个字节的空间,不过胜在简单。
具体描述就是:
在父类的结构体内插入一个额外的特殊命名的标记成员。再实现一个宏,这个宏有两个参数,分别为子类对象和想转化的父类结构体名。这个宏相当于是重新实现了强制类型转化。在子类退化为父类的场合用这个宏替代之前的强制类型转换。
下面看具体的代码:
//OOC.h
#ifndef _INCLUDE_OOC_H
#define _INCLUDE_OOC_H
typedef unsigned char OOC_START_T;
//作为基类的结构体一定要有一个名为OOC_START_XXX 的成员 XXX表示结构体名
//在子类退化为父类的场合用 OOC_BASE宏代替强制类型转换
#define OOC_BASE(p_s,base) ((base*)(&p_s->OOC_START_##base)) //子类对象退化为基类对象
//在父类特化为子类的场合用OOC_SON宏代替强制类型转换
#define OOC_SON(p_b,son,base) ((son*)((char*)p_b-(char*)&((son*)0)->OOC_START_##base))//在某些场合需要从父类对象特化为子类对象,比如实现了一个通用链表节点父类,通过节点访问子类属性时
#endif
//teacher.h
#ifndef _INCLUDE_TEACHER_H_
#define _INCLUDE_TEACHER_H_
#include "OOC.h"
typedef void (* teach_t)(void);
#define TEACHER_BASE \
OOC_START_T OOC_START_teacher_t;\
teach_t teaching
typedef struct techer_s
{
TEACHER_BASE;
}teacher_t;
#endif
//writer.h
#ifndef _INCLUDE_WRITER_H_
#define _INCLUDE_WRITER_H_
#include "OOC.h"
typedef void (* write_t)(void);
#define WRITER_BASE\
OOC_START_T OOC_START_writer_t;\
write_t writing
typedef struct writer_s
{
WRITER_BASE;
}writer_t;
#endif
//ryan.h
#ifndef _INCLUDE_RYAN_H_
#define _INCLUDE_RYAN_H_
#include "OOC.h"
#include "teacher.h"
#include "writer.h"
typedef struct ryan_s
{
TEACHER_BASE;
WRITER_BASE;
}ryan_t;
ryan_t * create_ryan(void);
#endif
//juliet.h
#ifndef _INCLUDE_JULIET_H_
#define _INCLUDE_JULIET_H_
#include "OOC.h"
#include "teacher.h"
#include "writer.h"
typedef struct juliet_s
{
TEACHER_BASE;
WRITER_BASE;
}juliet_t;
juliet_t * create_juliet(void);
#endif
//ryan.c
#include "ryan.h"
#include <stdio.h>
static ryan_t instance;
static void ryan_teaching(void)
{
printf("I am ryan, i teaching math !\n");
}
static void ryan_writing(void)
{
printf("I am ryan, i am a writer use pen!\n");
}
ryan_t * create_ryan(void)
{
instance.teaching = ryan_teaching;
instance.writing = ryan_writing;
return &instance;
}
//juliet.c
#include "juliet.h"
#include <stdio.h>
static juliet_t instance; //这里可以理解为单例模式,多实例的实现方式可以用堆
static void juliet_teaching(void)
{
printf("I am juliet, i teaching English !\n");
}
static void juliet_writing(void)
{
printf("I am juliet, i am a writer use computer!\n");
}
juliet_t * create_juliet(void)
{
instance.teaching = juliet_teaching;
instance.writing = juliet_writing;
return &instance;
}
//main.c
#include "OOC.h"
#include "teacher.h"
#include "writer.h"
#include "ryan.h"
#include "juliet.h"
teacher_t* p_teachers[2]={0};
writer_t* p_writers[2]={0};
void write_talk(void)
{
p_writers[0]->writing();
p_writers[1]->writing();
}
void teacher_talk(void)
{
p_teachers[0]->teaching();
p_teachers[1]->teaching();
}
int main()
{
ryan_t* p_ryan = create_ryan();
juliet_t* p_juliet = create_juliet();
p_teachers[0]= OOC_BASE(p_ryan,teacher_t);
p_teachers[1]= OOC_BASE(p_juliet,teacher_t);
p_writers[0]= OOC_BASE(p_ryan,writer_t);
p_writers[1]= OOC_BASE(p_juliet,writer_t);
write_talk();
teacher_talk();
}
上面的代码定义了老师类和作家类两个基类。Ryan 是数学老师兼用笔写作的作家。Juliet是英语老师兼用电脑创造的作家。英语不好轻喷。