【C++】多重继承与虚继承

多重继承与虚继承

  • 1.单继承和多重继承的区别
  • 2.语法规则
        • 示例代码:多重继承子类指定父类的构造
        • 示例代码:多重继承子类隐藏父类的同名方法
  • 3.虚继承解决多重继承遇到的bug
        • 示例代码:环状继承引发的问题
    • 3.1 虚基类:
    • 3.2 语法规则:
    • 3.3 总结:普通继承跟虚继承的区别
    • 3.4 虚基类表:
        • 示例代码:虚继承跟普通继承(没有使用virtual)的区别

1.单继承和多重继承的区别

单继承:子类只有一个父类
多重继承:一个类如果具备了多个其它类的特点,就可以使用多重继承

情况一:子类继承了多个父类
圆桌: 继承圆和桌子
骡子: 继承马和驴
豹子: 继承猫科动物和哺乳动物
情况二:A派生出B,B派生出C C接着派生(重点)
直接父类:Cat就是波斯猫的直接父类
间接父类:Animal就是波斯猫的间接父类
Animal --》Cat --》波斯猫 --》其他猫
环状继承(菱形继承)
A动物
哺乳B C猫科
D豹子
产生的问题:
问题一:A被构建了多次,浪费了存储空间(希望A只构建一次)
问题二:二义性问题,通过D去调用A里面的方法有两条途径(一条通过B调用,还有一条通过C调用)

2.语法规则

class  子类的名字:public 父类1,public 父类2  //公有继承
{}
  • 子类大小: 所有父类大小之和+子类本身的大小,满足字节对齐
  • 构造函数调用顺序:多个父类从左到右调用
  • 析构函数调用顺序:多个父类从右到左调用
  • 指定调用父类的构造函数
roundtable(int newr, int  w,int h):circle(newr),desk(w,h)
{}

注意:指定的时候多个父类的顺序无所谓,最终父类构造函数调用的顺序以当初继承时候书写的左右顺序为准

示例代码:多重继承子类指定父类的构造
#include <iostream>
#include <cstring>
using namespace std;/*多重继承子类指定父类的构造*/
class Catamount  //猫科动物
{
public:Catamount(){cout<<"猫科构造"<<endl;}Catamount(int n){cout<<"猫科构造,带int参数: "<<n<<endl;}~Catamount(){cout<<"猫科析构"<<endl;}
};class Mammal //哺乳动物
{
public:Mammal(){cout<<"哺乳构造"<<endl;}Mammal(string name){cout<<"哺乳构造,带string的参数: "<<name<<endl;}~Mammal(){cout<<"哺乳析构"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public://情况1:部分指定,指定了哺乳动物,没有指定的依然使用无参构造// Leopard():Mammal("草")// Leopard():Catamount(666)//情况2:完全指定//       完全指定的时候,指定父类构造函数的顺序无所谓Leopard():Catamount(888),Mammal("肉")// Leopard():Mammal("肉"),Catamount(888){cout<<"豹子构造"<<endl;}~Leopard(){cout<<"豹子析构"<<endl;}
};int main(int argc,char **argv)
{Leopard l1;return 0;   
}/*
输出结果:
情况1:哺乳构造,带string的参数: 草      /     哺乳构造猫科构造                        /     猫科构造,带int参数: 666豹子构造                        /     豹子构造豹子析构                        /     豹子析构猫科析构                        /     猫科析构哺乳析构                        /     哺乳析构
情况2:哺乳构造,带string的参数: 肉猫科构造,带int参数: 888豹子构造豹子析构猫科析构哺乳析构
*/
  • 子类出现跟父类同名的方法(子类隐藏了父类的同名方法)
round.getarea();          //圆桌自己的getarea
round.Circle::getarea();  //圆桌对象调用父类Circle的getarea  
round.Desk::getarea();    //圆桌对象调用父类Desk的getarea  
示例代码:多重继承子类隐藏父类的同名方法
#include <iostream>
#include <cstring>
using namespace std;/*多重继承子类隐藏父类的同名方法
*/
class Catamount  //猫科动物
{
public:void eat(){cout<<"猫科动物吃"<<endl;}
};class Mammal //哺乳动物
{
public:void eat(){cout<<"哺乳动物吃"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public:void eat(){cout<<"豹子吃"<<endl;}
};int main(int argc,char **argv)
{Leopard l1;l1.eat(); //两个父类的eat都被隐藏//调用父类的eatl1.Mammal::eat();l1.Catamount::eat();return 0;   
}/*
执行结果:豹子吃哺乳动物吃猫科动物吃
*/

3.虚继承解决多重继承遇到的bug

示例代码:环状继承引发的问题
#include <iostream>
#include <cstring>
using namespace std;/*环状继承引发的问题?问题1:Animal被构建多次浪费了存储空间,C++希望Animal只构建一次问题2:豹子调用eat方法提示二义性*/
class Animal
{
public:Animal(){cout<<"Animal无参构造了"<<endl;}void eat(){cout<<"Animal eat"<<endl;}
};class Catamount:public Animal  //猫科动物
{
public:Catamount(){cout<<"Catamount无参构造"<<endl;}
};class Mammal:public Animal //哺乳动物
{
public:Mammal(){cout<<"Mammal无参构造"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public:Leopard(){cout<<"Leopard无参构造"<<endl;}
};int main(int argc,char **argv)
{Leopard l1;//编译报错:提示eat有二义性// l1.eat();  // error: request for member ‘eat’ is ambiguous//解决问题2:但是无法解决问题1l1.Mammal::eat();l1.Catamount::eat();return 0;   
}/*
执行结果:
问题1: 可以看出Animal类被创建的2次Animal无参构造了Mammal无参构造Animal无参构造了Catamount无参构造Leopard无参构造问题2: 可以解决报错,但无法解决问题1Animal无参构造了Mammal无参构造Animal无参构造了Catamount无参构造Leopard无参构造Animal eatAnimal eat
*/

3.1 虚基类:

\quad 虚基类使得从多个类(B和C)它们的基类相同,共同的虚基类是(A)派生出(D)的对象只继承一个基类对象(通俗的讲就是子类使用virtual继承了父类,这个父类就是虚基类)
在这里插入图片描述

3.2 语法规则:

class  子类:virtual public  父类
class  子类:public virtual 父类
{};
virtualpublic的次序无关紧要

3.3 总结:普通继承跟虚继承的区别

  • 虚继承可以解决二义性和A被构建多次这两个问题,普通继承不能解决;虚继承通过增加一个指针(浪费了一点存储空间),换取了更高的效率
  • 只要一个类虚继承了其它类,那么该类所有的对象中都会新增一个指针,该指针专门用来指向系统中虚基类表的首地址

3.4 虚基类表:

C++中专门用来存放虚基类地址的一种数据结构
底层原理如下:
在这里插入图片描述

示例代码:虚继承跟普通继承(没有使用virtual)的区别
#include <iostream>
#include <cstring>
using namespace std;/*虚继承的底层原理(虚继承跟普通继承(没有使用virtual)的区别):1.如果一个子类虚继承了另外一个父类,子类的地址空间中会多出一个指针2.指针的作用:用来指向虚基类表的首地址
*/
class Animal
{
public:Animal(){cout<<"Animal无参构造了"<<endl;}void eat(){cout<<"Animal eat"<<endl;}
};class Catamount:virtual public Animal  //猫科动物
{
public:Catamount(){cout<<"Catamount无参构造"<<endl;}private:int m_age;
};class Mammal:virtual public Animal //哺乳动物
{
public:Mammal(){cout<<"Mammal无参构造"<<endl;}
};class Leopard:public Mammal,public Catamount
{
public:Leopard(){cout<<"Leopard无参构造"<<endl;}
};int main(int argc,char **argv)
{cout<<"猫科类的大小:"<<sizeof(Catamount)<<endl;  // 猫科类的大小:16cout<<"哺乳类的大小:"<<sizeof(Mammal)<<endl;     // 哺乳类的大小:8return 0;   
}/*
执行结果:Leopard l1;l1.eat(); 时,输出:Animal无参构造了Mammal无参构造Catamount无参构造Leopard无参构造Animal eat
*/

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

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

相关文章

GCC编译/连接/优化等选项

1. GCC编译/连接/优化等选项 1. GCC编译/连接/优化等选项 1.1. 简介1.2. 常用选项 1.2.1. -c -E -S -o1.2.2. -L<path> -l<library>1.2.3. -D<macro>1.2.4. -I<path> 1.3. 代码生成和优化 1.3.1. -std<standard>1.3.2. -shared1.3.3. -fPIC1.3.…

FFmpeg 压缩视频文件

文章目录 FFmpeg 压缩视频文件基本压缩命令&#xff08;保持 MP4 格式&#xff09;转换为其他格式示例&#xff1a;关键参数说明&#xff1a;额外优化选项&#xff1a; 在FFmpeg中使用多线程加速1. 帧级多线程 (frame-level multithreading)2. 切片级多线程 (slice-level multi…

Ubuntu 系统通过防火墙管控 Docker 容器

Ubuntu 系统通过防火墙管控 Docker 容器指南 一、基础防火墙配置 # 启用防火墙 sudo ufw enable# 允许 SSH 连接&#xff08;防止配置过程中断联&#xff09; sudo ufw allow 22/tcp二、Docker 配置调整 # 编辑 Docker 配置文件 sudo vim /etc/docker/daemon.json配置文件内…

虚拟机新增硬盘,与数据挂载

我有个虚拟机&#xff0c;当时选择了独立文件&#xff0c;现在遇到个问题&#xff0c;硬盘不够了&#xff0c;索性加了一个新硬盘&#xff0c;现在想把数据库的数据映射到这个新的硬盘处理。 罗列硬盘 lsblk我得是sdb是新硬盘 2. 分区 sudo fdisk /dev/sdb交互操作&#xff…

go语言学习 第10章:面向对象编程

第10章&#xff1a;面向对象编程 面向对象编程&#xff08;OOP&#xff09;是一种编程范式&#xff0c;它使用“对象”来表示数据和方法&#xff0c;并通过类来定义对象的结构和行为。Go语言虽然不是传统的面向对象语言&#xff0c;但它通过结构体&#xff08;struct&#xff…

android计算器代码

本次作业要求实现一个计算器应用的基础框架。以下是布局文件的核心代码&#xff1a; <LinearLayout xmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_height"match_parent"andr…

Go 语言接口详解

Go 语言接口详解 核心概念 接口定义 在 Go 语言中&#xff0c;接口是一种抽象类型&#xff0c;它定义了一组方法的集合&#xff1a; // 定义接口 type Shape interface {Area() float64Perimeter() float64 } 接口实现 Go 接口的实现是隐式的&#xff1a; // 矩形结构体…

我们来学mysql -- 8.4版本记录慢查询

记录慢查询 开启慢查询的配置查看慢查询状态动态开启慢查询日志永久开启配置log_throttle_queries_not_using_indexes 记录慢查询对性能的影响实际案例说明第一条记录第二条记录第三条记录第四条记录 开启慢查询的配置 查看慢查询状态 - 执行 show variables like slow_quer…

2025 年中国大学生程序设计竞赛全国邀请赛(郑州)暨第七届CCPC河南省大学生程序设计竞赛(补题)

文章目录 前言F、幻形之路G、直径与最大独立集H&#xff0c;树论函数M&#xff0c; 川陀航空学院总结 前言 本次比赛&#xff0c;只能说太多没接触的知识了&#xff0c;还有太容易被题面吓住。 F、幻形之路 题目链接&#xff1a;幻形之路 解题思路&#xff1a; 对于这一题只…

如何使用k8s安装redis呢

在Kubernetes (k8s) 上安装Redis 在Kubernetes上安装Redis有几种方法&#xff0c;下面我将介绍两种常见的方式&#xff1a;使用StatefulSet直接部署和使用Helm chart部署。 一、安装redis 1.1 拉去ARM镜像&#xff08;7.4.2&#xff09; docker pull registry.cn-hangzhou.ali…

SpringBoot的5种日志输出规范策略

在企业级应用开发中&#xff0c;合理规范的日志记录是系统稳定运行、问题排查和性能优化的关键保障。 SpringBoot作为流行的Java开发框架&#xff0c;提供了强大而灵活的日志支持&#xff0c;但如何建立统一、高效的日志输出规范却是许多团队面临的挑战。 本文将介绍SpringBo…

Python Cookbook-7.11 在 PostgreSQL 中储存 BLOB

任务 需要将 BLOB 存入一个 PostgreSQL 数据库。 解决方案 PostgreSQL7.2 以及更新的版本支持大对象,而psycopg 模块提供了二进制转义函数: import psycopg,cPickle #连接到数据库,用你的本机来测试数据库,并获得游标 connection = psycopg.connect("dbname = test…

Android端口转发

如上图所示&#xff0c;有一个Android设备&#xff0c;Android设备里面有主板&#xff0c;主板上有网络接口和Wi-Fi&#xff0c;网络接口通过网线连接了一个网络摄像头&#xff0c;这就跟电脑一样&#xff0c;电脑即可以通过网线接入一个网络&#xff0c;也可以同时用Wi-Fi接入…

Unity基础-协程

Unity基础-协程 四、协程 概述 协程&#xff08;Coroutine&#xff09;&#xff0c;本质上并不是多线程&#xff0c;而是在当前线程中将代码分时执行&#xff0c;不卡主线程。可以理解为&#xff0c;协程会把可能使主线程卡顿的程序分时分布进行。 协程通常用来&#xff1a;…

UniApp组件封装,2025年最新HarmonyOS鸿蒙模块化开发项目式教程

一、环境配置与前置条件 ‌开发工具要求‌ HBuilderX 4.64&#xff08;鸿蒙插件已预装&#xff09;DevEco Studio 5.0.3.400&#xff08;真机调试必备&#xff09;鸿蒙离线SDK&#xff08;通过HBuilderX导入&#xff0c;每个项目独立配置&#xff09; ‌项目初始化 # 创建Vu…

C++ 精简知识点

目录 一、核心语法 1.指针VS引用 2. 类与对象&#xff08;必写代码&#xff09; 3. 继承与多态&#xff08;必写代码&#xff09; 4. 模板&#xff08;必写代码&#xff09; 5.智能指针 6. 异常处理&#xff08;必写结构&#xff09; 二、简答题速记 三、考试应急策略 一…

7.Vue的compute计算属性

3.8. 【computed】 作用&#xff1a;根据已有数据计算出新数据&#xff08;和Vue2中的computed作用一致&#xff09;。 <template><div class"person">姓&#xff1a;<input type"text" v-model"firstName"> <br>名&am…

在VSCode中借助AI丰富C++Qt应用程序

随着国内外各类自动化编程助手的普及&#xff0c;作为传统桌面C开发者&#xff0c;也要及时地用上这样强大的工具。考虑到网速问题&#xff0c;国外的服务时断时续&#xff0c;还是倾向于使用一些国产的大语言模型助手。我们今天就来看看在VSCode下使用大语言模型辅助Qt开发。 …

Java八股文——JVM「内存模型篇」

JVM的内存模型介绍一下 面试官您好&#xff0c;您问的“JVM内存模型”&#xff0c;这是一个非常核心的问题。在Java技术体系中&#xff0c;这个术语通常可能指代两个不同的概念&#xff1a;一个是JVM的运行时数据区&#xff0c;另一个是Java内存模型&#xff08;JMM&#xff0…

RabbitMQ 高可用与可靠性保障实现

RabbitMQ 高可用与可靠性保障实现详解 一、高可用架构设计1.1 集群部署模式1.2 镜像队列&#xff08;Mirrored Queue&#xff09; 二、可靠性保障机制2.1 消息持久化2.2 确认机制&#xff08;Confirm & Ack&#xff09;2.3 死信队列&#xff08;DLX&#xff09; 三、容灾与…