C++继承之虚继承实例

1 概述

  通过继承机制,可以利用已有的对象类型来定义新的对象类型。所定义的新的对象类型不仅仅拥有新定义的成员,而且还同时拥有旧的成员。我们称已存在的用来派生新类的类为基类,又称为父类。由已存在的类派生出的新类称为派生类,又称为子类。

2 对象访问作用域

作用域:

  • public(公共作用域) 对象自身、派生类内部,对象外部都可以访问。
  • protected(保护作用域) 对象自身、派生类内部可以访问。
  • private(私有作用域) 只有对象自身可以访问。

说明:

  • 友元函数和友元类不受上述作用域限制。
  • protected(保护作用域)就是为了派生使用的。

3 继承

继承分类:

  • public继承 派生类中父类public成员还是public成员。
  • protected继承 派生类中父类public成员变成protected成员。
  • private继承 派生类中父类public成员变成private成员。
  • 多重继承 派生类可以从多个父类派生。
  • 虚继承

3.5 虚继承

虚继承是面向对象编程中的一个重要概念,特别是在C++语言中用于解决多重继承带来的问题。当两个或更多的类继承自同一个基类时,如果没有使用虚继承,每个派生类都会包含基类的一个副本,这可能导致数据冗余和内存浪费。虚继承通过确保基类在派生类中只有一个共享的副本,来解决这个问题。

虚继承的工作原理:

虚基类指针:在C++中,使用虚继承时,编译器会在派生类中创建一个虚基类指针(vptr),以及一个虚基表(vtable)。虚基表存储了到虚基类成员的偏移量。访问虚基类成员:当需要通过派生类访问虚基类的成员时,派生类通过其虚基类指针查找虚基表,从而找到成员的地址并访问之。

虚继承的优点:

  • 节省内存:通过共享虚基类的单一实例,避免了数据冗余。
  • 避免二义性:在多重继承中,使用虚继承可以减少成员访问的二义性问题。

3.5.1 例子

在C++中,使用virtual关键字来声明一个继承关系为虚继承,例如:

#include <iostream>
#include <stdint.h>struct IoBase
{IoBase(uint8_t *data, uint32_t maxSize): data_(data), maxSize_(maxSize), w_pos_(0), r_pos_(0){std::cout << "IoBase is called" << std::endl;}void print(){if(isEmpty()){std::cout << "Stream is empty!" << std::endl;return;}std::cout << "Stream:\n  " << std::hex;for(uint32_t i = r_pos_; i < w_pos_; i++)std::cout << static_cast<int>(data_[i]) << " ";std::cout << std::dec << std::endl;}uint32_t writeSpace() const { return maxSize_ - w_pos_; }uint32_t size() const { return w_pos_ - r_pos_; }bool isEmpty() const { return w_pos_ == r_pos_; }
protected:uint8_t* data_;uint32_t w_pos_;uint32_t r_pos_;
private:uint32_t maxSize_;
};struct Ostream : virtual IoBase
{Ostream(uint8_t *data, uint32_t maxSize): IoBase(data, maxSize){std::cout << "Ostream is called" << std::endl;}Ostream& operator << (uint32_t value){if(writeSpace() >= sizeof(value)){data_[w_pos_++] = (uint8_t)(value & 0xFF);data_[w_pos_++] = (uint8_t)((value >> 8) & 0xFF);  data_[w_pos_++] = (uint8_t)((value >> 16) & 0xFF); data_[w_pos_++] = (uint8_t)((value >> 24) & 0xFF); }return *this;}uint32_t writePos() const { return w_pos_; }
};struct Istream : virtual IoBase
{Istream(uint8_t *data, uint32_t maxSize): IoBase(data, maxSize){std::cout << "Istream is called" << std::endl;}void setSize(uint32_t size) { w_pos_ = r_pos_ + size; }Istream& operator >> (uint32_t &value){if(size() >= sizeof(value)){value = (data_[r_pos_ + 3] << 24) | data_[r_pos_ + 2] << 16 | data_[r_pos_ + 1] << 8 | data_[r_pos_];r_pos_ += sizeof(value);}return *this;}
};struct IOStream :  Ostream,  Istream
{IOStream(uint8_t *data, uint32_t maxSize): IoBase(data, maxSize), Ostream(data, maxSize), Istream(data, maxSize){}
};int main(int argc, char *argv[])
{uint8_t data[24];uint32_t a = 0x12345678;uint32_t b;IOStream io(data, sizeof(data));std::cout << "a=0x" << std::hex << a << std::endl;io << a;io.print();io >> b;std::cout << "b=0x" << std::hex << b << std::endl;io.print();return 0;
}

说明:

  • IOStream需要显示调用IoBase构造函数,如下所示:
struct IOStream :  Ostream,  Istream
{IOStream(uint8_t *data, uint32_t maxSize): IoBase(data, maxSize), Ostream(data, maxSize), Istream(data, maxSize){}
};

3.5.2 运行结果

IoBase is called
Ostream is called
Istream is called
a=0x12345678
Stream:78 56 34 12
b=0x12345678
Stream is empty!

3.5.3 分析

从运行结果看:

  • 父类IoBase构造函数指调用了一次。
  • IOStream继承了Ostream和Istream功能,并且共享一份IoBase的数据。

3.5.4 总结

  • 虚继承主要用在多继承场景中,单继承或只有一层继承关系时不会发挥作用。
  • 过度使用虚继承可能会增加额外的开销,因为需要维护虚基类的地址偏移量和查找虚基类成员的位置。

我们可以看到虚继承不仅是一个技术手段,也是C++语言中解决多重继承问题的一个有效方法。

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

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

相关文章

外包干了17天,技术倒退明显

先说情况&#xff0c;大专毕业&#xff0c;18年通过校招进入湖南某软件公司&#xff0c;干了接近6年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落&#xff01; 而我已经在一个企业干了四年的功能…

设计模式|装饰器模式(Decorator Pattern)

文章目录 结构优缺点优点缺点适用场景示例装饰器模式(Decorator Pattern)是一种结构型设计模式,它允许在不改变原始对象的基础上,动态地给对象添加新的功能或责任。这种模式是通过创建一个包装对象,也就是装饰器,来包裹真实的对象,然后在装饰器中添加新的行为或功能。这…

web自动化测试系列-selenium xpath定位方法详解(六)

1.xpath介绍 XPath 是一门在 XML 文档中查找信息的语言。XPath 用于在 XML 文档中通过元素和属性进行导航。而html中也应用了这种语言 &#xff0c;所以 &#xff0c;我们定位html页面元素时也会用到xpath这种方法 。 2.xpath定位方式 xpath主要通过以下四种方法定位 &#…

白帽工具箱:Metasploit框架中的db_nmap扫描艺术

&#x1f31f;&#x1f30c; 欢迎来到知识与创意的殿堂 — 远见阁小民的世界&#xff01;&#x1f680; &#x1f31f;&#x1f9ed; 在这里&#xff0c;我们一起探索技术的奥秘&#xff0c;一起在知识的海洋中遨游。 &#x1f31f;&#x1f9ed; 在这里&#xff0c;每个错误都…

有趣的css - 太极八卦图

大家好&#xff0c;我是 Just&#xff0c;这里是「设计师工作日常」&#xff0c;今天分享的是用css 实现一个动态的太极八卦图。 《有趣的css》系列最新实例通过公众号「设计师工作日常」发布。 目录 整体效果核心代码html 代码css 部分代码 完整代码如下html 页面css 样式页面…

Netty出坑记

NIO&#xff1a; 一个线程处理多个请求 BIO&#xff1a; 阻塞 netty 编码解码 TFO&#xff1a; 校验cookie合法性&#xff0c;不合法 TCP流程 设计QQ&#xff1a; 登录过程&#xff0c;client TCP协议向server发送信息&#xff0c;HTTP协议下载信息 发消息&#xff1a;clie…

JS实现大数相加

概述 在JavaScript中&#xff0c;进行大数相加时&#xff0c;由于JavaScript的Number类型有一定的精度限制&#xff0c;直接相加可能会导致精度损失 解决方案 将大数转换为字符串&#xff0c;使用字符串拼接的方式实现大数相加&#xff0c;对相加后的字符串从低位到高位逐位求…

云服务器上Docker启动的MySQL会自动删除数据库的问题

一、问题说明 除了常见的情况&#xff0c;例如没有实现数据挂载&#xff0c;导致数据丢失外&#xff0c;还需要考虑数据库是否被攻击&#xff0c;下图 REVOVER_YOUR_DATA 就代表被勒索了&#xff0c;这种情况通常是数据库端口使用了默认端口&#xff08;3306&#xff09;且密码…

Harmony鸿蒙南向驱动开发-SDIO

SDIO&#xff08;Secure Digital Input and Output&#xff09;由SD卡发展而来&#xff0c;与SD卡统称为MMC&#xff08;MultiMediaCard&#xff09;&#xff0c;二者使用相同的通信协议。SDIO接口兼容以前的SD卡&#xff0c;并且可以连接支持SDIO接口的其他设备。 运作机制 …

力扣HOT100 - 54. 螺旋矩阵

解题思路&#xff1a; 设置四个边界 class Solution {public List<Integer> spiralOrder(int[][] matrix) {if (matrix.length 0) return new ArrayList<Integer>();int l 0;int r matrix[0].length - 1;int t 0;int b matrix.length - 1;List<Integer>…

动手学习深度学习(李沐)

文章目录 04.数据操作 04.数据操作 创建数组 形状 每个元素的数据类型 每个元素的值 数据操作

PyCharm如何调出Run窗口的搜索功能

搜索快捷键 搜索&#xff08;查找&#xff09;的快捷键默认有两个 Ctrl F Alt F3 只需要点击运行窗口的区域&#xff0c;再使用上面的快捷键就好了。 也可以在代码中查找&#xff0c;也是上述操作。 如果按了没反应怎么办&#xff1f; 1、可能是有些软件的某些功能的快捷…

使用Pandas解决问题:对比两列数据取最大值的五种方法

目录 一、使用max方法 二、使用apply方法结合lambda函数 三、使用np.maximum函数 四、使用clip方法 五、使用where方法结合条件赋值 总结&#xff1a; 在数据处理和分析中&#xff0c;经常需要比较两个或多个列的值&#xff0c;并取其中的最大值。Pandas库作为Python…

Linux(CentOS7)安装 Docker 以及 Docker 基本使用教程

目录 安装 基础依赖 安装 docker 开机自启 启动 docker 配置国内镜像源 使用教程 帮助命令 镜像命令 容器命令 容器终端 构建镜像 安装 基础依赖 如果直接安装 docker 时报错&#xff0c;提示缺少依赖&#xff0c;则根据提示将前置依赖安装即可&#xff0c;这里直…

计算机组成原理(存储器)

1、“821.2016T1(1)”&#xff0c;表示821真题&#xff0c;2016年的题&#xff0c;T1是 选择题/填空题/大题 的第一题&#xff0c;其他类似标记也是相通 2、个人小白总结自用&#xff0c;不一定适用于其他人&#xff0c;请自行甄别 3、有任何疑问&#xff0c;欢迎私信探讨&…

Stunnel网络加密服务

简介&#xff1a; Stunnel是一个用于创建SSL加密隧道的工具&#xff0c;针对本身无法进行TLS或SSL通信的客户端及服务器&#xff0c;Stunnel 可提供安全的加密连接。可以用于保护服务器之间的通信。您可以在每台服务器上安装Stunnel&#xff0c;并将其配置为在公网上加密传输数…

基于 SSM 数据结构课堂考勤管理系统的设计与实现

摘 要 高校的不断扩张让在校学生数量不断的增加&#xff0c;对于教师和管理人员的需求也在不断地增强&#xff0c;对日常的学生考勤管理的工作量也在日益增加&#xff0c;传统的人工点名签到的考勤管理模式已经给无法适用于当前高校考勤管理的需求&#xff0c;同时手动录入的…

C语言中的文件操作

C语言中的文件操作 1、文件的打开 创建文件指针变量 File* pf;定义一个指向FILE类型数据的指针变量&#xff0c;可以使pf指向某个文件的文件信息区&#xff0c;通过文件指针变量就能够找到与它关联的文件 &#xff08;1&#xff09;文件的打开 使用fopen函数打开文件&#…

关于招聘项目的常用方法类(PHP版)

1、最低工资与最高工资的数字转化为 几千到几千的形式 /*** param $minwage 最低工资* param $maxwage 最高工资* param int $negotiable 0表示具体工资&#xff0c;1表示面议* return string|string[]*/ public function handle_wage($minwage, $maxwage, $negotiable 0){$w…

Vue3---基础3(组合式API,setup语法糖)

选项式API与组合式API 在Vue2内是选项式API&#xff08;OptionsAPI&#xff09; 在Vue3内是组合式API&#xff08;CompositionAPI&#xff09; 选项式API 示例代码 <script lang"ts"> export default {name: person,data() {return {name: "张杰",a…