C++回顾(九)——多继承

news2025/7/22 18:40:14

9.1 多继承

9.1.1 概念

  • 一个类有多个直接基类的继承关系称为多继承(多个父类)
  • 多继承声明语法
class  派生类名 : 访问控制  基类名1 ,  访问控制  基类名2 ,, 访问控制  基类名n
{
         数据成员和成员函数声明
}
  • 类 C 可以根据访问控制同时继承类 A 和类 B 的成员,并添加自己的成员

在这里插入图片描述
在这里插入图片描述

9.1.2 多继承的派生类的构造和访问

  • 多个基类的派生类构造函数可以用初始式调用基类构造函数初始化数据成员
  • 执行顺序与单继承构造函数情况类似。多个直接基类构造函数执行顺序取决于定派生类时指定的各个继承基类的顺序
    在这里插入图片描述
  • 一个派生类对象拥有多个直接或间接基类的成员。不同名成员访问不会出现二义性。如果不同的基类有同名成员,派生类对象访问时应该加以识别
    在这里插入图片描述

示例代码:

#include <iostream>

using namespace std;

class Airplane 
{
protected:
	int high;
public:
	Airplane()
	{
		cout << "飞机的构造函数" << endl;
		high = 100;
	}
	void show()
	{
		cout << "飞行高度 " << high << endl;
	}
};

class Ship
{
protected:
	int speed;
public:
	Ship()
	{
		cout << "轮船的构造函数" << endl;
		speed = 50;
	}
	void show()
	{
		cout << "航行的速度 " << speed << endl;
	}
};

class WaterPlane : public Ship, public Airplane   //多继承
{
public:
	WaterPlane()
	{
		cout << "水上飞机的构造函数" << endl;
	}
};

int main()
{
	WaterPlane w;   //先构造基类,再构造派生类,基类的构造顺序和继承顺序有关
	cout << sizeof(w) << endl;
	w.Airplane::show();
	w.Ship::show();

	return 0;
}

运行结果:
在这里插入图片描述

9.1.3 多继承的二义性

如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性。
在这里插入图片描述
示例代码:

#include <iostream>

using namespace std;

class TestA
{
public:
	int a[100];
};

class TestB : public TestA
{
public:
	int b;
};

class TestC : public TestA
{
public:
	int c;
};

class TestD : public TestB, public TestC
{
public:
	int d;
};

int main()
{
	TestD td;
	cout << sizeof(td) << endl;

    cout << &td << endl;
    cout << &td.TestB::a << endl;
    cout << &td.b << endl;
    cout << &td.TestC::a << endl;
    cout << &td.c << endl;
    cout << &td.d << endl;

	return 0;
}

运行结果:
在这里插入图片描述

9.1.4 虚继承

  • 如果一个派生类从多个基类派生,而这些基类又有一个共同的基类,则在对该基类中声明的名字进行访问时,可能产生二义性
  • 如果在多条继承路径上有一个公共的基类,那么在继承路径的某处汇合点,这个公共基类就会在派生类的对象中产生多个基类子对象
  • 要使这个公共基类在派生类中只产生一个子对象,必须对这个基类声明为虚继承,使这个基类成为虚基类。
  • 虚继承声明使用关键字 virtual
    在这里插入图片描述
    在这里插入图片描述
    示例代码:
#include <iostream>

using namespace std;

class TestA    //虚基类
{
public:
	int a;
};

class TestB : virtual public TestA
{
public:
	int b;
};

class TestC : virtual public TestA
{
public:
	int c;
};

class TestD : public TestB, public TestC
{
public:
	int d;
};

int main()
{
	TestD td;
	cout << sizeof(td) << endl;


	cout << "******" << endl;
	TestB tb;
	cout << sizeof(tb) << endl;
	cout << &tb << endl;
	cout << &tb.a << endl;
	cout << &tb.b << endl;
	
	cout << "*****" << endl;
	cout << &td << endl;
	cout << &td.a << endl;
	cout << &td.b << endl;
	cout << &td.c << endl;
	cout << &td.d << endl;


	return 0;
}

运行结果:
在这里插入图片描述

9.2 C++向上转型

9.2.1 将派生类对象赋值给基类对象

  • 赋值的本质是将现有的数据写入已分配好的内存中,对象的内存只包含了成员变量,所以对象之间的赋值是成员变量的赋值,成员函数不存在赋值问题

    运行结果也有力地证明了这一点,虽然有a=b;这样的赋值过程,但是 a.display() 始终调用的都是 A 类的 display() 函数。换句话说,对象之间的赋值不会影响成员函数,也不会影响 this 指针。

  • 将派生类对象赋值给基类对象时,会舍弃派生类新增的成员,也就是“大材小用”,如下图所示:
    在这里插入图片描述
    可以发现,即使将派生类对象赋值给基类对象,基类对象也不会包含派生类的成员。

  • 这种转换关系是不可逆的,只能用派生类对象给基类对象赋值,而不能用基类对象给派生类对象赋值。理由很简单,基类不包含派生类的成员变量,无法对派生类的成员变量赋值。同理,同一基类的不同派生类对象之间也不能赋值。

在这里插入图片描述
示例代码:

#include <iostream>

using namespace std;

class Parent
{
private:
	int a;
};

class Child : public Parent
{
private:
	int b;
};

int main()
{
	int a = 1.11;
	double b = 2;

	Parent p;   
	Child c;

	p = c;    //只能将派生类对象赋值给基类对象   派生类引用赋值给基类引用   派生类指针赋值给基类指针 (向上转型)
	//c = p;

	return 0;
}

9.2.2 将派生类指针赋值给基类

9.3 类型兼容性原则

  • 类型兼容规则是指在需要基类对象的任何地方,都可以使用公有派生类的对象来替代。通过公有继承,派生类得到了基类中除构造函数、析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。
  • 类型兼容规则中所指的替代包括以下情况:
    (1)子类对象可以当作父类对象使用
    (2)子类对象可以直接赋值给父类对象
    (3)子类对象可以直接初始化父类对象
    (4)父类指针可以直接指向子类对象
    (5)父类引用可以直接引用子类对象
  • 在替代之后,派生类对象就可以作为基类的对象使用,但是只能使用从基类继承的成员。类型兼容规则是多态性的重要基础之一。

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

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

相关文章

Git在某个节点切出新分支

操作前&#xff0c;必须先备份分支&#xff0c;避免丢失代码&#xff01;&#xff01;&#xff01;&#xff01; 操作前&#xff0c;必须先备份分支&#xff0c;避免丢失代码&#xff01;&#xff01;&#xff01;&#xff01; 操作前&#xff0c;必须先备份分支&#xff0c;避…

Mr. Cappuccino的第46杯咖啡——Maven多模块项目可插拔式打包部署方案

Maven多模块项目可插拔式打包部署方案需求调研前准备项目结构模块之间的依赖关系项目pom文件项目代码代码运行效果方案调研需要实现的效果解决方案代码实现打包运行效果完整打包测试插拔式打包测试最佳实践项目结构测试运行效果完整打包测试插拔式打包测试需求 早期的【train-h…

吐血整理,自动化测试pytest测试框架,资深测试带你少走弯路......

目录&#xff1a;导读前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09;前言 Pytest框架详解 py…

ledcode----丢失的数字

目录 题目截图&#xff1a; 题目接口&#xff1a; 第一种解法&#xff1a; 思路&#xff1a; 第二种解法&#xff1a;差值法 思路&#xff1a; 第三种解法&#xff1a;位运算异或法 关于异或操作符的预备知识&#xff1a; 思路&#xff1a; 例子&#xff1a;输入数组[0…

海思3531a pjsip交叉编译

学习文档&#xff1a; PJSUA2 Documentation — PJSUA2 Documentation 1.0-alpha documentationhttps://www.pjsip.org/docs/book-latest/html/index.html ./configure --prefix/opensource/pjproject-2.12/build3531a \ --host/opt/hisi-linux/x86-arm/arm-hisi…

MySQL全解[集群篇]

目录日志错误日志二进制日志格式查看删除查询日志慢查询日志主从复制原理docker搭建分库分表拆分策略垂直拆分垂直分库垂直分表水平拆分水平分库水平分表实现技术MyCat2mysql2对比mycat1.xdocker运行mycat2日志 错误日志 错误日志是 MySQL 中最重要的日志之一&#xff0c;它记…

NYUv2生成边界GT(2)

由NYUv2生成边界GT(1)可知&#xff0c;我们每张GT图片都生成一个对应的.bin文件。存放在D:\datasets\data_proc\train\edge_labels_40文件夹下&#xff0c;下一步我们需要生成.png文件&#xff0c;即需要使用convert_bin_to_png.py。 # -*- coding: utf-8 -*- import numpy as…

【Azure 架构师学习笔记】-Azure Storage Account(1)- Queue Storage

本文属于【Azure 架构师学习笔记】系列。 本文属于【Azure Storage Account】系列。 接上文 【Azure 架构师学习笔记】-Azure Storage Account&#xff08;1&#xff09;-类型简介 前言 Azure Storage Queues 是一个专门用来处理基于云环境队列的Azure 服务。每个队列都维护着…

Netty之ChannelHandler初解

目录 目标 Netty版本 Netty官方API 实战 Netty服务器 入栈ChannelHandler读入数据顺序案例 出栈ChannelHandler写出数据顺序案例 ChannelHandlerContext和NioSocketChannel写入数据时有什么不同 Pipeline添加多个ChannelHandler有什么意义 目标 掌握ChannelHandler基…

海康工业相机使用教程

工业相机使用一、硬件连接1、准备材料2、相机供电&#xff08;1&#xff09;区分电源适配器正负极&#xff08;2&#xff09;连接相机电源线缆&#xff08;3&#xff09;连接完成后&#xff0c;相机蓝色灯常亮则成功3、软件连接&#xff08;1&#xff09;MVS客户端下载地址&…

你真的会在阳光下拍照片么?

你好&#xff0c;我是小麥。 上节课我们讲了如何通过影子判断光的质量&#xff0c;也就是光的软硬&#xff0c;这节课我们来接着说一说光的方向和环境光的实际运用。 虽然在现实生活里&#xff0c;我们可能没有从软硬的角度观察过光线&#xff0c;但我相信你在拍照片的时候一…

第九章:Java集合

第九章&#xff1a;Java集合 9.1&#xff1a;Java集合框架概述 数组、集合都是对多个数据进行存储(内存层面&#xff0c;不涉及持久化)操作的结构&#xff0c;简称Java容器。 数组存储多个数据方面的特点 一旦初始化以后&#xff0c;其长度就确定了。数组一旦定义好&#xff…

计算机操作系统:实验三存储管理程序设计

一、目的和要求 目的 存储管理的主要功能之一是合理地分配主存空间。请求页式管理是一种常用的虚拟存储管理技术。 本实验的目的是通过请求页式存储管理中页面置换算法的模拟设计&#xff0c;来了解虚拟存储技术的特点&#xff0c;掌握请求页式存储管理的页面置换算法。 要求…

数字工厂管理系统的应用案例

数字工厂管理系统是制造企业应用数字化工厂技术实现研发设计数字化、生产准备数字化、 生产制造数字化、运营管理数字化和营销服务数字化的重要手段&#xff0c;即通过应用数字相关技术提升产品全生命周期数字化水平&#xff0c;从而提升企业经营的可靠性、安全性和经济性。 任…

C++回顾(十)—— 多态

10.1 问题引出 10.1.1 如果子类定义了与父类中原型相同的函数会发生什么&#xff1f; 函数重写 在子类中定义与父类中原型相同的函数&#xff0c;函数重写只发生在父类与子类之间 重载与重写区别&#xff1a; &#xff08;1&#xff09;重载&#xff1a;同一个作用域&#xf…

A、力扣刷题——数组

提示&#xff1a;这是力扣上数组类题目里的简单题&#xff0c;按顺序做下来的23道题。 第一题&#xff1a; 关键词&#xff1a;原地修改&#xff0c;有序数组 我的答案&#xff1a; &#xff08;for循环&#xff09; &#xff08;1&#xff09;有序数组 class Solution{pu…

平安大视野前瞻2023投资策略:资产格局“危中有机”,关注科技、绿色、安全领域

3月3日&#xff0c;平安私人银行全新云端沙龙《平安大视野》第一站在杭州举办&#xff0c;活动聚焦2023年宏观经济展望&#xff0c;邀请中国首席经济学家论坛理事、鹏扬基金首席经济学家陈洪斌&#xff0c;平安私人银行首席策略分析师彭伟伟就国内外宏观经济变化和资产配置策略…

干货系列:高通量测序后的下游实验验证方法——m6A RNA甲基化篇|易基因

大家好&#xff0c;这里是专注表观组学十余年&#xff0c;领跑多组学科研服务的易基因。此前&#xff0c;我们分享了m6A RNA甲基化研究的数据挖掘思路&#xff08;点击查看详情&#xff09;&#xff0c;进而筛选出m6A修饰目标基因。做完MeRIP-seq测序后&#xff0c;如果需要对分…

【JavaWeb】Servlet详解

文章目录1. 前置知识2.servlet生命周期2.1 默认情况下&#xff0c;服务器启动时&#xff0c;servlet对象并没有被创建2.2 用户执行一次请求2.3用户执行第二次请求2.4 3,4,5,6....次请求2.5 关闭服务器3.servlet方法解析4.适配器模式改造servlet4.1不使用servlet模式4.2使用适配…

【微服务】(十五)—— Seata 的部署和集成

文章目录1. 部署Seata的tc-server1.1 下载Seata1.2 解压1.3 修改配置1.4 在nacos添加配置1.5 创建数据库表1.6 启动TC服务2. 微服务集成seata2.1 引入依赖2.2 修改配置文件3. TC服务的高可用和异地容灾3.1 模拟异地容灾的TC集群3.2 将事务组映射配置到nacos3.3 微服务读取nacos…