嵌入式养成计划-40----C++菱形继承--虚继承--多态--模板--异常

九十四、菱形继承

94.1 概念

  • 菱形继承又称为钻石继承,
  • 是由公共基类派生出多个中间子类,又由中间子类共同派生出汇聚子类,
  • 汇聚子类会得到多份中间子类从公共基类继承下来的数据成员,会造成空间浪费,没有必要。

所以存在一个问题:

  • 汇聚子类会得到多份中间子类从公共基类继承下来的数据成员,会造成空间浪费,没有必要。
  • 会多次对公共基类的数据成员初始化,或者释放。
  • 如何避免?

94.2 形式

   A     --------公共基类/   \
B     C   -------中间子类\   /D     --------汇聚子类
  • 上面那个问题的解决方法:虚继承

九十五、虚继承

95.1 作用

  • 使汇聚子类仅获得一份经中间子类从公共基类继承下来的数据成员。

95.2 格式

  • 关键字 :virtual
  • 在中间子类的继承方式前加 virtual
class 类名:virtual 继承方式 类名   //中间子类,可多继承
{中间子类自己的内容;
};

95.3 注意

  • 虚继承之后,只保留一份中间子类从公共基类继承下来的数据成员,
  • 但是不知道保留哪个中间子类的,所以就会自动调用公共基类的无参构造函数,
  • 如果想使用公共基类的有参构造函数,则需要在汇聚子类中调用公共基类的有参构造函数。

九十六、多态

  • 静态多态(在编译时加载)—> 如 :函数重载
  • 动态多态(在运行时加载)

96.1 啥是多态

  • 多态 :一种形式 拥有 多种状态
  • 例如 :一个人,在不同环境下有着不同的状态,也有不同的 属性 和 功能

  • 多态:父类的指针或者引用,指向或者初始化子类的对象,调用子类对父类重写的函数,进而使用子类的功能。

96.2 函数重写

  • 要求 :
    1. 两个类之间必须要有继承关系
    2. 子类和父类有同名同类型的函数
    3. 父类中的该函数必须是虚函数

96.3 虚函数

  • 关键字 :virtual
  1. 在函数前加 virtual ----->虚函数
  2. 虚函数满足继承,
    如果父类中函数是虚函数,那么继承到子类中,该函数还是虚函数,
    如果子类继续被继承,那么“孙类”中的该函数还虚函数…

96.4 赋值兼容规则

  • 父类的指针或者引用,可以指向或者初始化子类的对象
  • 父类指针指向的仅仅只是子类中继承父类的那段空间
    在这里插入图片描述

96.5 多态中,实现函数重写的原理

  1. 类中有虚函数时,虚函数都会有一个虚指针
  2. 虚指针在类的最前面,指向了虚函数表,虚函数表里记录虚函数
  3. 虚指针和虚函数表是实现多态的重要机制
    在这里插入图片描述

96.6 虚析构函数

  • 因为父类指针指向子类对象,只作用与子类从父类继承下来的那片特殊空间,
  • 释放父类指针,只会把父类指针作用的那块空间释放,子类自己拓展的空间没有得到释放,从而造成内存泄漏。

虚析构函数 :如果把父类中析构函数设置成虚析构函数,那么子类拓展的空间就会被一起释放,虚析构函数也满足继承。

示例 :

#include <iostream>
using namespace std;class Person
{
private:string name;
public:Person() {}Person(string name):name(name){}virtual ~Person(){}  //虚析构函数
};
class Stu:public Person
{
private:int id;
public:Stu() {}Stu(string n, int id):Person(n),id(id){}~Stu(){}
};
int main()
{Person *ptr = new Stu("zhangsan", 1001);delete ptr;  //如果没有虚析构函数的话,只释放父类指针作用的空间,子类//拓展的空间并没有得到释放,会造成内存泄漏。解决方案:虚析构函数return 0;
}

96.7 纯虚函数

  • 当父类中的虚函数只用来被子类重写,并且没有需要去完成的功能,那么一般将该虚函数设置成纯虚函数。

  • 格式:

    virtual 函数返回值类型 函数名(形参列表) = 0 ; //纯虚函数
    //纯虚函数 是在父类中声明,子类中实现
    

    在这里插入图片描述

96.8 抽象类

  • 概念: 抽象类中至少有一个纯虚函数,抽象类不能具体的实例化一个对象,一般是用来被继承的。
    不能实例化对象,只能执行子类对象

  • 如果父类中有纯虚函数,表示父类是抽象类,
    子类继承后,如果没有对父类中纯虚函数做重写,则子类也是一个抽象类,不能实例化一个对象。

例如 :

#include <iostream>
using namespace std;class A
{
private:int a;
public:virtual void show() = 0;//纯虚函数  
};class B :public A
{
private:int b;
public:
};int main()
{//B a;  不能实例化一个对象return 0;
}

96.9 C++中虚函数与纯虚函数的区别

  1. 虚函数和纯虚函数可以定义在同一个类中,含有纯虚函数的类被称为抽象类,而只含有虚函数的类不能被称为抽象类。

  2. 虚函数可以被直接使用,也可以被子类重载以后,以多态的形式调用,而纯虚函数必须在子类中实现该函数才可以使用,因为纯虚函数在基类有声明而没有定义。

  3. 虚函数和纯虚函数都可以在子类中被重载,以多态的形式被调用。

  4. 虚函数和纯虚函数通常存在于抽象基类之中,被继承的子类重载,目的是提供一个统一的接口。

  5. 虚函数的定义形式:virtual{};纯虚函数的定义形式:virtual { } = 0;在虚函数和纯虚函数的定义中不能有static标识符,原因很简单,被static修饰的函数在编译时要求前期绑定,然而虚函数却是动态绑定,而且被两者修饰的函数生命周期也不一样。

九十七、模板

  • 模板就是建立一个通用的模具,大大提高代码的复用性。
  • C++除面向对象编程思想外,还有另一种编程思想,泛型编程,主要利用的技术是 模板
  • C++提供了两种重要的模板机制:函数模板 和 类模板

生活中的模板 :
在这里插入图片描述
在这里插入图片描述

97.1 模板的特点

  1. 模板是通用的,不是万能的
  2. 模板只是一个框架

97.2 函数模板

97.2.1 作用

  • 函数模板,就是建立一个通用的函数,
  • 其返回值类型,或者参数类型不具体制定,用一个虚拟的类型来代替。

97.2.2 格式

template<typename T>
函数的定义

如 :

template <typename T>
T fun(T x, T y)  //建立了一个通用的函数,实现数据类型之和
{return x+y;
}

template -------> 创建模板
typename -------> 表明其后是一种数据类型,typename还可以用class代替
T -----> 表示数据类型,也可以用其他代替

调用时 :

cout << fun(1,2) << endl;
cout << fun(1.3,1.4) << endl;
cout << fun('0', '1') << endl;

97.3 类模板

97.3.1 作用

  • 建立一个通用的类, 类中的 成员变量 的类型 不具体制定,用一个虚拟类型来代替

97.3.2 格式

template<typename T>
类的定义

template -------> 创建模板
typename -------> 表明其后是一种数据类型,typename还可以用class代替
T -----> 表示数据类型,也可以用其他代替

九十八、异常

  • 作用 :可以优雅的解决异常

  • 实现步骤

    1. try包裹可能产生异常的地方
    2. 在产生异常的条件下,用 throw抛出异常
    3. try后面的 catch语句中接收异常,并在 catch后的代码块中处理异常

示例 :

#include <iostream>
using namespace std;int fun(int x, int y)
{if(y!=0){return x/y;}else{throw -1;  //抛出异常}
}
int main()
{try{fun(9,0); //把可能发生异常的地方用try包裹起来cout << "hello 啊" << endl;        }catch (int e){if(e == -1){cout << "分母为0,不合法" << endl;}}return 0;
}

小作业:

比喻:
动物园的讲解员和动物表演
动物园里有一位讲解员,他会为每种动物表演做简单的介绍,如狮子、大象、猴子等。提示:在这个场景中,我们可以将动物比作是不同的类,而每种动物表演则是类中的函数。讲解员则是一个基类,他可以根据每种动物的特点和表演,进行相应的介绍。
具体过程如下:定义一个基类 Animal,其中有一个虛函数perform(),用于在子类中实现不同的表演行为。

我写的

#include <iostream>
using namespace std;// base_class
class Animal
{
private:string name;
public:Animal() {}Animal(string name):name(name) {}Animal(const Animal &other):name(other.name){}Animal &operator=(const Animal &other){name = other.name;return *this;}virtual ~Animal(){}virtual void perform() = 0;string get_name(){return this->name;}
};class Lion:virtual public Animal
{
public:Lion() {}Lion(string name):Animal(name) {}Lion(const Lion &other):Animal(other){}Lion &operator=(const Lion &other){Animal::operator=(other);return *this;}~Lion(){}void perform() {cout << Animal::get_name() + " : " << "河东狮吼" << endl;}
};class Elephant:virtual public Animal
{
public:Elephant() {}Elephant(string name):Animal(name) {}Elephant(const Elephant &other):Animal(other){}Elephant &operator=(const Elephant &other){Animal::operator=(other);return *this;}~Elephant(){}void perform() {cout << Animal::get_name() + " : " << "象群践踏" << endl;}
};class Monkey:virtual public Animal
{
public:Monkey() {}Monkey(string name):Animal(name) {}Monkey(const Monkey &other):Animal(other){}Monkey &operator=(const Monkey &other){Animal::operator=(other);return *this;}~Monkey(){}void perform() {cout << Animal::get_name() + " : " << "专业偷桃" << endl;}
};int main()
{Animal *p = nullptr;Lion l("狮子狗");Elephant e("孟获");Monkey m("孙猴子");p = &l;p->perform();p = &e;p->perform();p = &m;p->perform();return 0;
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/103826.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

工程师必须记住的电路元件符号及英语翻译

很多电子小白第一次接触印刷电路板&#xff08;PCB&#xff09;时&#xff0c;总会头痛那些密密麻麻的元件字母符号&#xff0c;这些电路元件符号基本上都是采用英语缩写&#xff0c;下面我们来看看这些电路元件的英语符号有哪些&#xff1f; 电阻器&#xff08;Resistor&#…

C++入门指南:类和对象总结友元类笔记(下)

C入门指南:类和对象总结友元类笔记&#xff08;下&#xff09; 一、深度剖析构造函数1.1 构造函数体赋值1.2 初始化列表1.3 explicit关键字 二、static成员2.1 概念2.2 特性 三、友元3.1 友元函数3.2 友元类 四、 内部类4.1 概念4.2 特征 五、拷贝对象时的一些编译器优化六、深…

Linux进阶-加深进程印象

目录 进程 进程状态转换 进程状态 启动新进程 system()函数 system.c文件 Makefile文件 执行过程 fork()函数 函数原型 fork.c文件 Makefile文件 执行过程 exec系列函数 函数原型 execl.c文件 Makrfile文件 执行过程 终止进程 exit()函数和_exit()函数 头…

机器人制作开源方案 | 杠杆式6轮爬楼机器人

1. 功能描述 本文示例将实现R281b样机杠杆式6轮爬楼机器人爬楼梯的功能&#xff08;注意&#xff1a;演示视频中为了增加轮胎的抓地力&#xff0c;在轮胎上贴了双面胶&#xff0c;请大家留意&#xff09;。 2. 结构说明 杠杆式6轮爬楼机器人是一种专门用于爬升楼梯或不平坦地面…

【elasticsearch】elasticsearch8.0.1使用rpm包安装并启用TLS

背景 公司的业务需要在加密的情况下使用&#xff0c;为此&#xff0c;研究测试了一下es8是如何启用TLS的。以下是测试使用过程。 x-pack了解 在 Elasticsearch 7.11.0 版本及更高版本中&#xff0c;X-Pack 功能在默认情况下已经整合到 Elastic Stack 的各个组件中&#xff0…

Element-UI的使用——表格el-table组件去除边框、滚动条设置、隔行变色、去除鼠标悬停变色效果(基于less)

// Element-ui table表格去掉所有边框,如下&#xff1a; // 备注&#xff1a;若去掉所有边框&#xff0c;可自行将头部边框注释掉即可 // 该样式写在style scoped外面在el-table 中添加class"customer-table"类名 //去掉每行的下边框/deep/ .el-table td.el-table__c…

LCR 161.连续天数最高销售额

​​题目来源&#xff1a; leetcode题目&#xff0c;网址&#xff1a;LCR 161. 连续天数的最高销售额 - 力扣&#xff08;LeetCode&#xff09; 解题思路&#xff1a; 动态规划。对于第 i 个元素 sales[i]&#xff0c;若以第 i-1 个元素 sales[i-1] 为结尾的最大连续和 f(n-2)…

使用js怎么设置视频背景

要使用JavaScript设置网页的视频背景&#xff0c;你需要将视频元素添加到你的HTML文档中&#xff0c;然后使用JavaScript来控制它 首先&#xff0c;在你的HTML文件中添加一个 <video> 元素 <video id"video-background" autoplay muted loop><sourc…

勒索病毒最新变种.Malloxx勒索病毒来袭,如何恢复受感染的数据?

导言&#xff1a; 勒索病毒已经成为网络威胁的一个突出问题。其中&#xff0c;.Malloxx勒索病毒是一个危险的勒索软件&#xff0c;它能够加密你的数据文件&#xff0c;使其无法访问。本文91数据恢复将向您介绍.Malloxx勒索病毒的特点&#xff0c;以及如何恢复被其加密的数据文…

【MySQL】表的内连和外连

文章目录 一. 内连接二. 外连接1. 左外连接2. 右外连接 一. 内连接 利用where子句对两种表形成的笛卡尔积进行筛选&#xff0c;其实就是内连接的一种方式 另一种方式是inner join select 字段 from 表1 inner join 表2 on 连接条件 and 其他条件现在有如下表 mysql> desc…

M2芯片的Mac上安装Linux虚拟机——提前帮你踩坑

M2芯片的Mac上安装Linux虚拟机——提前帮你踩坑 1. 前言1.1 系统说明1.2 Linux系统选择——提前避坑1.3 下载vmware_fusion1.3.1 官网下载1.3.2 注册 CAPTCHA验证码问题1.3.3 产品说明 1.4 下载操作系统镜像1.4.1 下载centos&#xff08;如果版本合适的&#xff09;1.4.2 下载…

c 几种父进程主动终止子进程的方法

1.如子进程是循环状态 子进程循环等待键盘的输入&#xff0c;如父进程模拟键盘输入一个字符&#xff0c;子进程收到就跳出scanf&#xff08;&#xff09;。同理&#xff0c;如是socket 的accept&#xff08;&#xff09;等待&#xff0c;也可以发送一字符&#xff0c;让子进程…

Excel 自动提取某一列不重复值

IFERROR(INDEX($A$1:$A$14,MATCH(0,COUNTIF($C$1:C1,$A$1:$A$14),0)),"")注意&#xff1a;C1要空置&#xff0c;从C2输入公式 参考&#xff1a; https://blog.csdn.net/STR_Liang/article/details/105182654 https://zhuanlan.zhihu.com/p/55219017?utm_id0

c++视觉处理---直方图均衡化

直方图均衡化 直方图均衡化是一种用于增强图像对比度的图像处理技术。它通过重新分布图像的像素值&#xff0c;以使图像的直方图变得更均匀&#xff0c;从而提高图像的视觉质量。在OpenCV中&#xff0c;您可以使用 cv::equalizeHist 函数来执行直方图均衡化。以下是 cv::equal…

06-Zookeeper选举Leader源码剖析

上一篇&#xff1a;05-Zookeeper典型使用场景实战 一、为什么要看源码 提升技术功底&#xff1a;学习源码里的优秀设计思想&#xff0c;比如一些疑难问题的解决思路&#xff0c;还有一些优秀的设计模式&#xff0c;整体提升自己的技术功底深度掌握技术框架&#xff1a;源码看多…

Jenkins更换主目录

Jenkins储存所有的数据文件在这个目录下. 你可以通过以下几种方式更改&#xff1a; 使用你Web容器的管理工具设置JENKINS_HOME环境参数.在启动Web容器之前设置JENKINS_HOME环境变量.(不推荐)更改Jenkins.war(或者在展开的Web容器)内的web.xml配置文件. 这个值在Jenkins运行时…

ExcelBDD Python指南

在Python里面支持BDD Excel BDD Tool Specification By ExcelBDD Method This tool is to get BDD test data from an excel file, its requirement specification is below The Essential of this approach is obtaining multiple sets of test data, so when combined with…

【【萌新的SOC学习之自定义IP核 AXI4接口】】

萌新的SOC学习之自定义IP核 AXI4接口 自定义IP核-AXI4接口 AXI接口时序 对于一个读数据信号 AXI突发读 不要忘记 最后还有拉高RLAST 表示信号的中止 实验任务 &#xff1a; 通过自定义一个AXI4接口的IP核 &#xff0c;通过AXI_HP接口对PS端 DDR3 进行读写测试 。 S_AXI…

软件设计之抽象工厂模式

抽象工厂模式指把一个产品变成一个接口&#xff0c;它的子产品作为接口的实现&#xff0c;所以还需要一个总抽象工厂和它的分抽象工厂。 下面我们用一个案例去说明抽象工厂模式。 在class中可以选择super类和medium类&#xff0c;即选择一个产品的子类。在type中可以选择产品的…

c++处理图像---绘制物体的凸包:cv::convexHull

绘制物体的凸包&#xff1a;cv::convexHull cv::convexHull 是OpenCV中用于计算点集的凸包&#xff08;convex hull&#xff09;的函数。凸包是包围点集的最小凸多边形&#xff0c;该多边形的所有内部角都小于或等于 180 度。 cv::convexHull 函数的基本用法如下&#xff1a;…