用C实现多重继承的简单方案

本文介绍了一种在C语言中实现继承和多态性的方法,通过结构体嵌套和宏定义,创建了一个允许子类作为父类使用的系统。代码示例展示了如何处理多重继承,包括创建教师和作家类,并创建具有双重身份的Ryan和Juliet实例。通过宏OOC_BASE和OOC_SON进行类型转换,使得子类能够被当作父类操作。
摘要由CSDN通过智能技术生成

继承是为了实现多态,即可以把子类当父类来用。
我们一般在父类中声明接口,在子类中实现接口。所谓接口,就是一个个函数组成的集合。
以上观点,不喜勿喷。

下面言归正传
思路:
用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是英语老师兼用电脑创造的作家。英语不好轻喷。

在这里插入图片描述

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值