C++继承技术

news2025/1/11 14:53:55

方法覆盖

virtual关键字

只有在基类中声明为 virtual 的方法才能被派生类正确覆盖。关键字位于方法声明的开头,如下面的 Base 的修改版本所示:

class Base {
  public:
  	virtual void someMethod() {}
  protected:
  	int m_protectedInt { 0 };
  private:
  	int m_privateInt { 0 };
};

override关键字

要覆盖一个方法,你可以在派生类定义中重新声明它,就像它在基类中声明的那样,不同的是添加了 override 关键字并删除了 virtual 关键字。

class Derived : public Base {
  public:
  	void someMethod() override; // Overrides Base's someMethod()
  	virtual void someOtherMethod();
};

override 关键字的使用是可选的,但强烈建议使用。如果没有关键字,可能会意外地创建一个新的虚方法,而不是覆盖基类中的方法。

virtual是如何实现的

要了解如何避免方法隐藏,需要更多地了解 virtual 关键字的实际作用。在 C++ 中编译类时,会创建一个二进制对象,其中包含该类的所有方法。在非virtual的情况下,将控制转移到适当方法的代码直接硬编码在基于编译时类型调用方法的位置。这称为静态绑定,也称为早期绑定。

如果该方法被声明为virtual,则通过使用称为 vtable 或“虚表”的特殊内存区域调用正确的实现。每个具有一个或多个虚方法的类都有一个虚表,并且此类的每个对象都包含一个指向该虚表的指针。这个 vtable 包含指向虚方法实现的指针。这样,当在对象上调用方法时,指针跟随进入vtable,并在运行时根据对象的实际类型执行适当版本的方法。这称为动态绑定,也称为后期绑定。

为了更好地理解 vtables 如何使方法覆盖成为可能,以下面的 Base 和 Derived 类为例:

class Base {
  public:
  	virtual void func1();
  	virtual void func2();
  	void nonVirtualFunc();
};

class Derived : public Base {
  public:
  	void func2() override;
  	void nonVirtualFunc();
};

对于此示例,假设有以下两个实例:

Base myBase;
Derived myDerived;

图显示了两个实例的 vtable 外观的高级视图。 myBase 对象包含一个指向它的虚表的指针。该 vtable 有两个条目,一个用于 func1(),一个用于 func2()。这些条目指向 Base::func1() 和 Base::func2() 的实现。

myDerived 也包含指向其 vtable 的指针,该 vtable 也有两个条目,一个用于 func1(),一个用于 func2()。它的 func1() 入口指向 Base::func1(),因为 Derived 不会覆盖 func1()。另一方面,它的 func2() 入口指向 Derived::func2()。
在这里插入图片描述
请注意,两个 vtable 都不包含 nonVirtualFunc() 方法的任何条目,因为该方法不是virtual。

virtual的合理性

在某些语言中,例如 Java,所有方法都是自动virtual的,因此可以正确地覆盖它们。在 C++ 中,情况并非如此。反对在 C++ 中使一切virtual的论点,以及首先创建关键字的原因,与 vtable 的开销有关。要调用虚方法,程序需要通过解引用指向要执行的适当代码的指针来执行额外的操作。在大多数情况下,这是一个很小的性能损失,但 C++ 的设计者认为让程序员决定是否需要性能损失会更好,至少在当时是这样。如果该方法永远不会被覆盖,则无需将其虚拟化并降低性能。然而,对于今天的 CPU,性能影响是以纳秒的分数来衡量的,而且未来的 CPU 会越来越小。在大多数应用程序中,使用虚方法和避免使用虚方法之间不会有可衡量的性能差异。

尽管如此,在某些特定的用例中,性能开销可能过于昂贵,你可能需要有一个选项来避免这种情况。例如,假设你有一个具有虚方法的 Point 类。如果你有另一个存储数百万甚至数十亿个点的数据结构,则在每个点上调用虚拟方法会产生巨大的开销。在这种情况下,避免在 Point 类中使用任何虚方法可能是明智的。

每个对象的内存使用量也会受到轻微影响。除了方法的实现之外,每个对象还需要一个指向它的 vtable 的指针,它占用的空间很小。在大多数情况下这不是问题。但是,有时它确实很重要。再次以 Point 类和存储数十亿点的容器为例。在这种情况下,所需的额外内存变得很重要。

虚析构函数

除非你有特殊原因不这样做或类被标记为final,否则析构函数应标记为virtual。构造函数不能也不需要是virtual的,因为你总是在创建对象时指定要构造的确切类。

阻止覆盖

除了将整个类标记为 final 之外,C++ 还允许将单个方法标记为 final。此类方法不能在进一步的派生类中被覆盖。例如,从以下派生类覆盖 someMethod() 会导致编译错误:

class Base {
  public:
  	virtual ~Base() = default;
  	virtual void someMethod();
};

class Derived : public Base {
  public:
  	void someMethod() override final;
};

class DerivedDerived : public Derived {
  public:
  	void someMethod() override; // Compilation error.
};

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

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

相关文章

一图看懂 dis 模块:将 python 字节码反汇编为助记符,资料整理+笔记(大全)

本文由 大侠(AhcaoZhu)原创,转载请声明。 链接: https://blog.csdn.net/Ahcao2008 一图看懂 dis 模块:将 python 字节码反汇编为助记符,资料整理笔记(大全) 🧊摘要🧊模块图🧊类关系图…

chatgpt赋能Python-python_plt_散点图

Python plt散点图:学习数据可视化的有力武器 Python是一种广泛使用的编程语言,广泛应用于数据科学,数据分析,计算机视觉等领域。而在数据可视化方面,Python也提供了很多强大的工具,其中plt散点图是一种非常…

Chatbot UI老外在用的gpt网页版 搭建方法分享!

新建了一个网站 https://ai.weoknow.com/ 每天给大家更新可用的国内可用chatGPT资源 Chatbot UI 高仿ChatGPT官网,中文还支持贼好,界面美观度间距还需要打磨。是老外做的吗? ​ 环境部署 更新环境 apt update -y && apt upg…

09 - 进程长参数编程

---- 整理自狄泰软件唐佐林老师课程 查看所有文章链接:(更新中)Linux系统编程训练营 - 目录 文章目录 1. 短选项扩展编程1.1 再论进程参数(短选项)1.2 进程短选项示例 2. 进程长参数编程2.1 进程长参数示例2.2 进程长参…

MATLAB NAN或INF无效点去除 (14)

MATLAB NAN或INF无效点去除 (14) 一、算法介绍二、算法实现1.代码(含注释说明)2.效果(无效点去除前后点坐标展示)一、算法介绍 仅就一般情况来说,激光点云受到测量影响,可能会产生无效点,即坐标值为NAN或者INF等,这种点会严重干扰一些几何特征,例如法向等的计算,因…

HummerRisk V1.1.0 发布

HummerRisk V1.1.0发布: 重构了新的Dashboard,新增报告中心,增加新的 Linux 主机系统的安全扫描、安全审计功能。增加部分Docker相关的主机检测,镜像仓库新增公有云阿里云、腾讯云类型,新增镜像分组管理等功能&#x…

chatgpt赋能Python-python_os拷贝文件

Python os拷贝文件 – 从简介到实现 Python os库是一个经常使用的工具,它是Python的标准库,提供了与操作系统进行交互的函数和方法。其中,os拷贝文件是其常用的功能之一,可以用来实现文件备份、文件复制等等操作。接下来&#xf…

pthread多线程: 线程泄漏的检测

文章目录 1. 目的2. 什么是线程泄漏3. pthread 线程泄漏例子3.1 代码3.2 编译和运行3.3 简要分析 4. 检测线程泄漏4.1 编译链接时传入参数 -fsanitizethread4.2 确认 TSAN_OPTIONS 环境变量 5. 修复线程泄漏5.1 方法1: 主线程等待子线程5.2 方法2:子线程…

k8s网络如何连接?

在k8s中网络连接可以分为 容器与容器: 所有在pod中的容器表现为在同一个host,他们之间可以通过端口进行连接 pod与pod: 因为每个pod都有一个ip,因此pod可以通过ip进行直接连接 在不同主机上pod究竟是如何连接的呢?毕竟pod ip只是虚拟的&…

Vue+Element-ui实现表格导出和导入

表格导出,填写数据,导入表格 需求:表格导出,填写数据,导入数据表格文件存储在前端表格文件不存储 需求:表格导出,填写数据,导入数据 分析需求: (1&#xff0…

【Leetcode60天带刷】day01——704.二分查找、27.移除元素

题目: 704. 二分查找 Leetcode原题链接:力扣704.二分查找 思考历程与知识点: 考查二分查找能力,注意mid的取值。 注意: 右端点的大小,需要在数组长度上-1。也就是nums.size()-1,因为下标是从…

chatgpt赋能Python-python_numpy_转置

Python Numpy 转置 - 高效处理数据的必备技巧 作为一名专注于Python编程的工程师,你可能已经知道了 Python 编程语言的优雅以及Numpy 库的高效操作。在进行数值计算和数据处理方面,Numpy 库已成为 Python 可以与其他编程语言匹敌的主要原因之一。其中一…

Vue 3 第二十二章:组件十(组件高级特性-组件的渲染函数和JSX/TSX语法)

文章目录 1. 渲染函数2. JSX / TSX 语法2.1. 基本使用2.2. 使用 vue 中的语法2.2.1. {} 语法2.2.2. v-model 使用2.2.3. v-show 使用2.2.4. v-if 不支持,实现v-if功能2.2.5. v-for 不支持,实现 v-for 功能2.2.6. v-bind 不支持,模拟 v-bind2.…

AWD竞赛全流程解析

AWD(Attack With Defense,攻防兼备)是一个非常有意思的模式,你需要在一场比赛里要扮演攻击方和防守方,攻者得分,失守者会被扣分。也就是说,攻击别人的靶机可以获取 Flag 分数时,别人会被扣分,同…

汇编十三、串口

1、通信相关概念 (1)单工:只能接收或只能发送数据。 (2)半双工:既能发送数据,也能接收数据,但不能同时进行。 (3)全双工:可以同时进行发送和接收数据。 (4)单片机中常用的通信物理接口:I2C、SPI、USB、…

tushare单个股票过去五年的数据整理与预测

文章目录 前言:1. 导入相关包2. 数据预处理3. 构建模型3. 模型训练4. 检查数据6. 工作中其他常用包记录 前言: %md 在量化投资中,计算收益率是更常见的做法,而不是仅计算股价。计算收益率可以更好地反映投资的回报情况&#xff0c…

Pinctrl子系统_01_Pinctrl子系统介绍

本节介绍在Pinctrl子系统中,将会学习哪些内容。 Pinctrl作用 Pinctrl:Pin Controller,顾名思义,就是用来控制引脚的。 一个芯片有成百上千个引脚,这些引用要怎么配置,配置成什么功能,都是通P…

python+django网上书籍商城小说在线阅读分享下载系统k19is-vue

为了解决用户便捷地在网上购物以及下载文件,本文设计和开发了一个网页小说阅读系统。本系统是基于 B/S架构设计,Dango框架 ,Python技术的前台页面设计与实现,使用Mysql数据库管理来完成系统的相关功能。主要实现了管理员与用户的注…

ETSI TS-关于SCP80

描述 GPC_UICC Configuration_v2.0.pdf 中: 规范 ts_102.225v12.1.0 Secured packet structure for UICC based applications.pdf spi kic kid编码 7 TCP/IP 的实现 在发送安全数据包之前,发送实体应使用定义的推送机制打开 TCP/IP 连接 在 ETSI TS 102 226 [9] …

【MATLAB第34期】基于MATLAB的2023年棕熊优化算法BOA优化LSTM时间序列预测模型 优势明显,注释详细,绘图丰富

【MATLAB第34期】基于MATLAB的2023年棕熊优化算法BOA优化LSTM时间序列预测模型 优势明显,注释详细,绘图丰富,适合小白 一、代码优势 1.使用2023年棕熊算法BOA优化LSTM超参数(学习率,隐藏层节点,正则化系数…