继承

继承就是当创建一个类时,不需要重新编写新的数据成员和成员函数,只需指定新建的类继承了一个已有的类的成员即可。这个已有的类称为基类,新建的类称为派生类。 举个例子:人是动物,人具有动物的行为和属性,但人也有动物所不具备的行为和属性。

继承的实现

本实现使用了组合的方式,即把基类作为派生类的成员变量之一。 但是一定要将基类放在派生类首部,这要基类和派生类的内存首部分布才一致。

/* 基类 */
typedef struct _animal_t animal_t;  /* 动物类 */
struct _animal_t
{unsigned int stamina; /* 体力 */
};
/* 派生类 */
typedef struct _human_t human_t;    /* 人类 */
struct _human_t
{animal_t ancestor;            /* 继承基类 */unsigned int intelligence;    /* 智力 */
};

在派生类中的构造函数需要调用基类的构造函数用于初始化,然后再将构造函数创建的基类对象拷贝到派生类中。 但由于是浅拷贝,即只拷贝了地址,没有拷贝地址的内容。所以要在派生类中加入基类指针成员变量,用于在析构函数释放内存。

typedef struct _human_t human_t;/* 人类 */
struct _human_t
{animal_t ancestor;            /* 继承基类 */animal_t* p_ancestor;     /* 用于调用析构函数 */unsigned int intelligence;    /* 智力 */
};
human_t* human_born(void);      /* 构造函数 */
void human_die(human_t* this);  /* 析构函数 */
dfsdfs
human_t* human_born(void)
{human_t* this = malloc(sizeof(human_t));/* 将构造好的基类复制 */this->p_ancestor = animal_born();memcpy(&(this->ancestor), this->p_ancestor, sizeof(animal_t));this->intelligence = 60;printf("human_born: intelligence = %d\n", this->intelligence);return this;
}void human_die(human_t* this)
{printf("human_die\n");animal_die(this->p_ancestor);free(this);
}

由于在c语言下没有类型检查功能,在调用创建的类函数时就十分不安全,在基类加入基类类型名和类大小成员变量可以解决这个问题。 基类类型名用于判断调用函数对象是否继承自该类,而类大小用于判断调用函数对象是基类还是派生类。(该方法只适用于线性继承)

typedef struct _animal_t animal_t;  /* 动物类 */
struct _animal_t
{char* type_name;          /* 基类类型名 */unsigned int class_size;  /* 类大小 */unsigned int stamina; /* 体力 */
};
void act(void* this);       /* 动 */
typedef struct _human_t human_t;/* 人类 */
struct _human_t
{animal_t ancestor;            /* 继承基类 */animal_t* p_ancestor;     /* 用于调用析构函数 */unsigned int intelligence;    /* 智力 */
};
void learn(void* this);
void act(void* this)
{animal_t* animal_this = (animal_t*)this;char* type_name = animal_this->type_name;/* 判断调用函数对象是否继承自该类 */if(0 == strcmp(type_name, "animal_t")){printf("animal_act\n");animal_this->stamina -= 1;printf("stamina = %d\n", animal_this->stamina);}else{printf("can't act\n");}
}
void learn(void* this)
{human_t* human_this = (human_t*)this;char* type_name = human_this->ancestor.type_name;unsigned int class_size = human_this->ancestor.class_size;/* 判断调用函数对象是否继承自该类 *//* 避免基类调用函数 */if((0 == strcmp(type_name, "animal_t")) &&(class_size >= sizeof(human_t)));{human_this->intelligence += 1;printf("human_learn: intelligence+1\n");printf("intelligence = %d\n", human_this->intelligence);}else{printf("can't learn\n");}
}

多态

在上个例子中,人和动物都有会动的属性,但人的动作和动物的动作从表现上会有所不同。而多态就可以实现在同一个函数中,根据对象类型的不同,函数实现方式也不同。

多态的实现

c语言多态的实现,需要用到函数指针。函数名实际上是该函数代码存储空间的首地址,这个地址可以通过函数指针来存放。通过改变函数指针存储的地址就可以实现多态。

typedef struct _animal_t animal_t;
typedef void (*animal_act_t)(animal_t*);    /* 函数指针类型 */
typedef struct _animal_vtable_t     /* 虚函数表 */
{animal_act_t act;
}animal_vtable_t;struct _animal_t
{animal_vtable_t* vt;  /* 虚函数表指针存放到类中 */unsigned int stamina;
};
animal_t* animal_born(void);        /* 构造函数 */
void act(void* this);   /* 函数接口 */
void animal_die(animal_t* this);    /* 析构函数 */
static void animal_act(animal_t* this);/* 动物类的虚函数表 */
static animal_vtable_t __g_animal_vtable =
{/* 将实现函数的首地址(函数名)赋值给函数指针 */.act = animal_act,
};animal_t* animal_born(void)
{animal_t* this = malloc(sizeof(animal_t));this->vt = &__g_animal_vtable;this->stamina = 100;printf("animal_born: stamina = 100\n");return this;
}void act(void* this)
{/* 通过虚函数表的函数指针调用实现函数 */return ((animal_t*)this)->vt->act(this);
}/* 实现函数 */
static void animal_act(animal_t* this)
{if(this->stamina >= 30){this->stamina -= 5;printf("animal act: stamina-5\n");printf("stamina = %d\n", this->stamina);}else{this->stamina += 10;printf("animal rest: stamina+10\n");printf("stamina = %d\n", this->stamina);}
}void animal_die(animal_t* this)
{free(this);printf("animal_die\n");
}

示例代码

该代码将结合上述继承和多态的方法实现对基类函数进行重写:

/* animal.h */
#ifndef _ANIMAL_H_
#define _ANIMAL_H_#include <stdio.h>
#include <stdlib.h>
#include <string.h>typedef struct _animal_t animal_t;typedef void (*animal_act_t)(animal_t*);typedef struct _animal_vtable_t
{animal_act_t act;
}animal_vtable_t;struct _animal_t
{char* type_name;unsigned int class_size;animal_vtable_t* vt;unsigned int stamina;
};animal_t* animal_born(void);
void act(void* this);
void animal_die(animal_t* this);#endif  /* _ANIMAL_H_ */
/* animal.c */
#include "animal.h"static void animal_act(animal_t* this);static animal_vtable_t __g_animal_vtable =
{.act = animal_act,
};animal_t* animal_born(void)
{animal_t* this = malloc(sizeof(animal_t));this->type_name = malloc(sizeof("animal_t"));memcpy(this->type_name, "animal_t", sizeof(this->type_name));this->class_size = sizeof(animal_t);this->vt = &__g_animal_vtable;this->stamina = 100;printf("animal_born: stamina = 100\n");return this;
}void act(void* this)
{if(0 == strcmp(((animal_t*)this)->type_name, "animal_t")){return ((animal_t*)this)->vt->act(this);}printf("can't act\n");
}static void animal_act(animal_t* this)
{if(this->stamina >= 30){this->stamina -= 5;printf("animal act: stamina-5\n");printf("stamina = %d\n", this->stamina);}else{this->stamina += 10;printf("animal rest: stamina+10\n");printf("stamina = %d\n", this->stamina);}
}void animal_die(animal_t* this)
{free(this->type_name);free(this);printf("animal_die\n");
}
/* human.h */
#ifndef _HUMAN_H_
#define _HUMAN_H_#include "animal.h"typedef struct _human_t human_t;typedef void (*human_learn_t)(human_t*);typedef struct _human_vtable_t
{human_learn_t learn;
}human_vtable_t;struct _human_t
{animal_t ancestor;animal_t* p_ancestor;human_vtable_t* vt;unsigned int intelligence;
};human_t* human_born(void);
void learn(void* this);
void human_die(human_t* this);#endif  /* _HUMAN_H_ */
/* human.c */
#include "human.h"static void human_act(human_t* this);
static void human_learn(human_t* this);static animal_vtable_t __g_animal_vtable;
static human_vtable_t __g_human_vtable =
{.learn = human_learn,
};human_t* human_born(void)
{human_t* this = malloc(sizeof(human_t));this->p_ancestor = animal_born();memcpy(&(this->ancestor), this->p_ancestor, sizeof(animal_t));this->ancestor.class_size = sizeof(human_t);memcpy(&__g_animal_vtable, this->ancestor.vt, sizeof(animal_vtable_t));this->ancestor.vt = &__g_animal_vtable;this->ancestor.vt->act = human_act;this->vt = &__g_human_vtable;this->intelligence = 60;printf("human_born: intelligence = %d\n", this->intelligence);return this;
}void learn(void* this)
{char* type_name = ((human_t*)this)->ancestor.type_name;unsigned int class_size = ((human_t*)this)->ancestor.class_size;if((0 == strcmp(type_name, "animal_t")) &&(class_size >= sizeof(human_t)));{return ((human_t*)this)->vt->learn(this);}printf("can't learn\n");
}static void human_act(human_t* this)
{if(this->ancestor.stamina >= 30){this->ancestor.stamina -= 1;printf("human act: stamina-1\n");printf("stamina = %d\n", this->ancestor.stamina);}else{this->ancestor.stamina += 5;printf("human act: stamina+5\n");printf("stamina = %d\n", this->ancestor.stamina);}
}static void human_learn(human_t* this)
{this->intelligence += 1;printf("human_learn: intelligence+1\n");printf("intelligence = %d\n", this->intelligence);
}void human_die(human_t* this)
{printf("human_die\n");animal_die(this->p_ancestor);free(this);
}
/* main.c */
#include "animal.h"
#include "human.h"int main()
{printf("\nanimal monkey:\n");animal_t* monkey = animal_born();act(monkey);printf("\nanimal monkey learn:\n");learn(monkey);animal_die(monkey);printf("\nhuman qaq:\n");human_t* qaq = human_born();act(qaq);learn(qaq);human_die(qaq);system("pause");return 0;
}

结果如下:

用C语言实现C++ 继承与多态相关推荐

  1. Java语言高级-02继承与多态-第4节 多态

    多态的概述 面向对象的三大特征:封装性,继承性.多态性 extends继承或者implements实现,是多态性的前提 多态的格式与使用 package demo05; /* 代码当中体现多态性,其实 ...

  2. Java语言高级-02继承与多态-第7节内部类

    内部类的概念和分类 如果一个事物的内部包含另一个事物,那么这就是一个类内部包含另一个类 例如:身体和心脏的关系.又如:汽车和发动机的关系. 分类: 1.成员内部类 2.局部内部类(包含匿名内部类) 成 ...

  3. 【Java设计模式 面向对象设计思想】一 再谈面向对象和封装、抽象、继承、多态四大特性

    回看最初的目标:[Java设计模式 学习目标及大纲]高质量代码的标准及实现路径在这篇Blog里我们明确了什么是高质量的代码:易维护.易读.易扩展.灵活.简洁.可复用.可测试,也知道高质量代码的达成路径 ...

  4. 设计模式学习笔记(四)封装、继承、多态、抽象能解决什么问题?

    面向对象编程及面向对象编程语言的关键就是理解其四大特性:封装.抽象.继承.多态. 1. 封装(Encapsulation) 所谓封装性,封装也叫做信息隐藏或者数据访问保护.类通过暴露有限的访问接口,授 ...

  5. 理论二:封装、抽象、继承、多态分别可以解决哪些编程问题?

    王争<设计模式之美>学习笔记 文章目录 理论二:封装.抽象.继承.多态分别可以解决哪些编程问题? 封装(Encapsulation) 抽象(Abstraction) 继承(Inherita ...

  6. 【Python】Python语言学习:面向对象编程,类和对象,封装、继承和多态

    这一周Python语言学习,记录如下. 01 面向对象编OOP 1.1 为什么学习和应用OOP? 1 OOP适合更加复杂的需求分析和项目开发. 2 OOP具有更强大的封装能力. 3 OOP相比于面向过 ...

  7. C语言实现封装、继承、多态

    C语言实现封装.继承.多态 文章目录 C语言实现封装.继承.多态 一. 封装 二.继承 三. 多态 一. 封装 C语言中虽然没有类,但有struct和指针.我们可以在一个struct中存入数据和函数指 ...

  8. c语言实现c++的继承和多态

    继承和多态是C++的特性,它C语言没有这个特性. C++的三大特性:继承,多态,封装. 继承:分为公有(public)继承,私有(private)继承,保护(protected)继承. 用struct ...

  9. c语言编程继承例子,C语言模拟实现C++的继承与多态示例

    一.面向过程编程与面向对象编程的区别 众所周知,C语言是一种典型的面向过程编程语言,而C++确实在它的基础上改进的一款面向对象编程语言,那么,面向过程与面向对象到底有什么样的区别呢? [从设计方法角度 ...

  10. c语言错误封装,C语言实现的封装,继承,多态

    提到面向对象编程,我们想到的就是封装.继承.多态,但是其实这几个特性并不是只有面向对象语言才能实现,面向过程的C语言也是可以支持实现这三个特性的,下面我们来具体看下 封装1 2 3 4// point ...

最新文章

  1. 概率密度变换公式 雅可比矩阵_干货 | 从雅可比矩阵你还能得到什么?(雅可比矩阵下篇)...
  2. SAP QM 主检验特性主数据关键字段解释
  3. Vivado 随笔(2) 综合属性之use_dsp48?
  4. 在DLL编程中调用模版类时出现的类似class“XXX”需要有 dll 接口由 class“XXX”的客户端使用的warning的解决方案...
  5. docker部署xxl-job 通用反射执行器
  6. reflow 和 repaint
  7. cron 每年执行一次_循环执行定时任务crontab
  8. webParts与Web部件
  9. java finalize方法的使用
  10. openeim出去会有坏人把自己抓跑
  11. Data URL和图片,及Data URI的利弊
  12. 单片机ADC采样算法----中位值滤波法
  13. 为什么好多公司的开发语言从C#变成了JAVA
  14. delphi mysql类_Delphi MySQL数据库操作类
  15. 批处理计算n天前\后的日期
  16. mysql创建图书馆书库表格,mysql图书馆管理系统的数据库
  17. 内点法外点法matlab代码,分享:惩罚函数法(内点法、外点法)求解约束优化问题最优值...
  18. 720P、1080P、4K是什么意思?
  19. 基于微信小程序实现番茄钟专注时间项目演示【附项目源码+论文说明】
  20. 短距离的无线连接技术--蓝牙

热门文章

  1. 经典论文之OverFeat
  2. html变形金刚代码,百度变形金刚JS特效
  3. 2/3维向量叉乘意义判断二维平面点的相对位置向量法证明海伦公式
  4. 51开发板的功能及简单使用
  5. 计算机基础视频教程B站版
  6. 三维GIS引擎平台设计
  7. [代码审计]Textpattern4.8.4任意文件上传漏洞
  8. 软件测试初学者如何编写Jmeter测试脚本?
  9. JavaScript设计模式-观察者模式
  10. email 邮件发送源代码(c++实现)