MEC | 条款3 绝对不要以多态(polymorphically)方式处理数组

news2024/11/25 18:32:31

条款3 绝对不要以多态(polymorphically)方式处理数组

文章目录

  • 条款3 绝对不要以多态(polymorphically)方式处理数组
    • 继承
      • Example 打印基类-派生类数组
        • 传入BalencedBST 数组到函数
      • 删除基类-派生类数组
      • >>>>> 欢迎关注公众号【三戒纪元】 <<<<<

继承

继承(inheritance)最重要的性质之一就是可以通过“指向 base class objects”的 pointers 或 references,来操作 derived class objects。这就是多态(polymorphically)行为。

Example 打印基类-派生类数组

假设有个 基类 class BST(binary search tree) 以及一个继承自BST的 class BalancedBST:

class BST { ... };
class BalancedBST: public BST { ... };

在正式的代码中,BST及其基类可能会被设置为模板类(templates)。

考虑有个函数可以打印 BSTs 数组中的每一个 BST 内容:

void PrintBSTArray(ostream& s, const BST array[], int numElements) {
	for (int i = 0; i < numElements; ++i) {
		s << array[i]; // 假设 BST objects 有1个 operator<< 可用
	}
}

当你将1个由BST 对象组成的数组传递给此函数,是OK的

BST BSTArray[10];
...
PrintBSTArray(cout, BSTArray, 10); // OK

array[i]是1个“指针算术表达式”的简写,代表的是 *(array + i)

array 是个指针,指向数组起始处。

Qarray 所指内存和 array + i 所指内存两者相距多远?

Ai * sizeof(数组中对象)。因为 array[0] array[i] 之间有i个对象。

传入BalencedBST 数组到函数

加入传递到PrintBSTArray函数 的是1个由 BalancedBST 对象组成的数组,编译器会被误导

编译器假设数组中每个元素的大小是 BST 的大小,但其实每个元素大小是 BalancedBST 的大小。

由于 derived classes 通常比 base classes 有更多的 data members,所以 derived classes objects 通常都比 base classes objects 来的大。

因此,编译器为PrintBSTArray 函数所产生的指针算术表达式,对于 BalancedBST objects 所组成的数组而言就是错误的。结果不可预期。

测试:

class BST {
 public:
  int a{0};
};

class BalancedBST : public BST {
 public:
  int b{1};
  int c{2};
};

int main() {
  BST *bst = new BST[22];
  std::cout << "print BST array:" << std::endl;
  PrintBSTArray(bst, 5);

  BalancedBST* balTreeArray = new BalancedBST[33];
  std::cout << "print balTreeArray array:" << std::endl;
  PrintBSTArray(balTreeArray, 5);
}

结果:

print BST array
0
0
0
0
0
print balTreeArray array
0
1
2
0
1

删除基类-派生类数组

同理,如果尝试通过一个 base class 指针,删除1个由 derived class objects 组成的数组,同样存在上述问题:

// 删除1个数组,首先记录关于删除动作的消息
void DeleteArray(ostream& logStream, BST array[]) {
	logStream << "Deleting array at address "
	          << static_cast<void*>(array) << '\n';
	delete [] array;
}

// 产生1个 BalancedBST 数组
BalancedBST *balTreeArray = new BalancedBST[33];
... // work
DeleteArray(cout, balTreeArray);

上述代码,仍然存在1个“指针算术表达式”。

当数组被删除,数组中每1个元素的 destructor 都必须被调用,编译器其实看到的这样的句子delete[] array;,相当于看到:

// 将 *array 中的对象以其构造顺序的相反顺序加以析构
for (int i =  the number of elements in the array - 1; i >= 0; --i) {
	array[i].BST::~BST();
}

C++ 语言规范说,通过 base class 指针删除1个由 derived class objects 构成的数组,其结果未定义。

简单的说,多态(polymorphism) 和指针数组不能混用。

测试:

 int main() {
  BST* bst = new BST[2];
  std::cout << "print BST array:" << std::endl;
  PrintBSTArray(bst, 5);
  DeleteArray(bst);

  BalancedBST* balTreeArray = new BalancedBST[3];
  std::cout << "print balTreeArray array:" << std::endl;
  PrintBSTArray(balTreeArray, 5);
  DeleteArray(balTreeArray);
  std::cout << "Finish!" << std::endl;

  return 0;
 }

结果:

print BST array:
0
0
0
0
1041
BST destructor.
BST destructor.
print balTreeArray array:
0
1
2
0
1
BST destructor.
BST destructor.
BST destructor.
Finish!

所以删除 derived class 的时候,会调用基类的析构函数,解决这种办法需要将基类的析构函数设为虚函数。

详见《Effective C++》的《条款7 为多态基类声明virtual析构函数》


>>>>> 欢迎关注公众号【三戒纪元】 <<<<<

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

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

相关文章

8.1.tensorRT高级(3)封装系列-模型编译过程封装,简化模型编译代码

目录 前言1. 模型编译过程封装2. 问答环节总结 前言 杜老师推出的 tensorRT从零起步高性能部署 课程&#xff0c;之前有看过一遍&#xff0c;但是没有做笔记&#xff0c;很多东西也忘了。这次重新撸一遍&#xff0c;顺便记记笔记。 本次课程学习 tensorRT 高级-模型编译过程封装…

详细讲解如何在github上编辑个人主页?

在 GitHub 上编辑个人主页可以让您展示您的项目、技能和个人信息&#xff0c;以及与其他开发者互动。以下是详细的步骤来在 GitHub 上编辑个人主页&#xff1a; 创建 GitHub 账户 如果您还没有 GitHub 账户&#xff0c;首先需要注册一个。 登录到 GitHub 使用您的用户名和密…

StringBuilder的基本操作

1、为什么要学习StringBuilder? 1.1、String拼接100万次 String对象做字符串拼接&#xff0c;字符串直接拼接100万次&#xff0c;运行速度非常非常的慢&#xff0c;当数据量比较大的时候&#xff0c;一般不用字符串直接拼接 package stringdemo;public class StringTest {publ…

数据结构:选择排序

简单选择排序 选择排序是一种简单直观的排序算法。首先在未排序序列中找到最大&#xff08;最小&#xff09;的元素&#xff0c;存放到排序学列的其实位置&#xff0c;然后在剩余的未排序的元素中寻找最小&#xff08;最大&#xff09;元素&#xff0c;存放在已排序序列的后面…

9.利用matlab完成 泰勒级数展开 和 符号表达式傅里叶变换和反变换 (matlab程序)

1.简述 matlab之傅里叶变换和逆变换 首先生成一个方波&#xff08;或者其他组合波形&#xff09;&#xff0c;然后对这个信号做傅里叶变换&#xff0c;拆解到频域&#xff0c;可以看到这个信号是由哪些频率的信号叠加而来。 然后把频域信号&#xff0c;用傅里叶逆变换恢复到时…

Grafana Prometheus 通过JMX监控kafka 【2023最新方式】

第三方kafka exporter方案 目前网上关于使用Prometheus 监控kafka的大部分资料都是使用一个第三方的 kafka exporter&#xff0c;他的原理大概就是启动一个kafka客户端&#xff0c;获取kafka服务器的信息&#xff0c;然后提供一些metric接口供Prometheus使用&#xff0c;随意它…

编写守护进程

守护进程是一个后台进程&#xff0c;当操作系统启动时就可以运行的进程&#xff0c;当操作系统结束时结束的进程&#xff0c;与终端无关。 结果 不想要了就杀死

rt_hw_stack_init 线程栈初始化参数分析

rt_hw_stack_init rt-thread线程栈初始化参数分析 文章目录 rt_hw_stack_init rt-thread线程栈初始化参数分析Q:A:1. rt_hw_stack_init调用分析2. rt_hw_stack_init 实现分析2.1 向下增长型栈 rt_hw_stack_init 实现2.1 向上增长型栈 rt_hw_stack_init 实现 扩展知识&#xff1…

MybatisPlus中安装MybatisX插件及代码生成

创建一个新的模块 导入依赖 设置application.yml 连接数据库 点击下面红色框里面的&#xff0c;然后点apply&#xff0c;最后点ok 选好之后点next base path 根据自己的路径写 选完之后点finish 这样就自己生成了代码。 快速生成CRUD 选择方法后altenter 还可以多条件 方法…

NetSuite 固定资产租赁101

目录 前言 1.新租赁准则的相关内容 1.1 主要变化 1.2 IFRS 16/ASC 842/CAS 21的区别与联系 1.3 新租赁准则实行的意义 2.NetSuite中的租赁功能 2.1 概述 2.2 设置 2.2.1 相关科目设置 2.2.2 资产类型设置 2.3 功能详细说明 2.3.1 案例一 2.3.2 案例二 3.新租赁准则…

kafka 02——三个重要的kafka客户端

kafka 02——三个重要的kafka客户端 1. 前言1.1 关于 Kafka 的安装1.2 常用客户端简介1.3 依赖 2. AdminClient2.1 Admin Configs2.2 AdminClient API2.2.1 设置 AdminClient 对象2.2.2 创建 topic 获取 topic 列表2.2.3 删除topic2.2.4 查看 topic 的描述信息2.2.5 查看 topi…

小白带你部署LNMP分布式部署

目录 前言 一、概述 二、LNMP环境部署 三、配置nginx 1、yum安装 2、编译安装 四、安装 1、编译安装nginx 2、网络源 3、稍作优化 4、修改配置文件vim /usr/local/nginx/conf/nginx.conf 5、书写测试页面 五、部署应用 前言 LNMP平台指的是将Linux、Nginx、MySQL和…

Spring Boot + Vue3前后端分离实战wiki知识库系统<十二>--用户管理单点登录开发一

目标&#xff1a; 在上一次Spring Boot Vue3前后端分离实战wiki知识库系统&#xff1c;十一&#xff1e;--文档管理功能开发三我们已经完成了文档管理的功能模块开发&#xff0c;接下来则开启新模块的学习---用户登录&#xff0c;这块还是有不少知识点值得学习的&#xff0c;…

谈谈语音助手

目录 1.什么是语音助手 2.语音助手的发展过程 3.现在有哪些成熟的语音助手 4.语音助手对人类发展的影响 1.什么是语音助手 语音助手是一种能够通过语音交互与用户进行沟通和执行任务的虚拟助手。它基于人工智能和自然语言处理技术&#xff0c;能够理解用户的语音指令&#x…

LeetCode 36题:有效的数独

题目 请你判断一个 9 x 9 的数独是否有效。只需要 根据以下规则 &#xff0c;验证已经填入的数字是否有效即可。 数字 1-9 在每一行只能出现一次。数字 1-9 在每一列只能出现一次。数字 1-9 在每一个以粗实线分隔的 3x3 宫内只能出现一次。&#xff08;请参考示例图&#xff…

MEC | 条款4 非必要不提供 default constructor

条款4 非必要不提供 default constructor 文章目录 条款4 非必要不提供 default constructorclasses 必须有默认构造函数&#xff1f;Example1. 产生数组解决方法 2.不适用于 template-based container clases3.虚基函数 探讨>>>>> 欢迎关注公众号【三戒纪元】 …

CANoe自动化工程的搭建

基于XMLCAPL建立自动化工程 1、导入ini文件2、新建 Test Environment3、报告类型4、代码编写 1、导入ini文件 工程的配置的文件&#xff0c;配置DUT相关信息&#xff0c;具体视工程而编写内容。 2、新建 Test Environment 1、新建XML测试用例环境 2、导入XML测试用例文件 …

vulnhub靶机Deathnote

难度&#xff1a;easy 下载地址&#xff1a;https://download.vulnhub.com/deathnote/Deathnote.ova 主机发现 arp-scan -l 端口扫描 nmap --min-rate 10000 -p- 192.168.21.140 进一步查看目标的端口的服务和版本 nmap -sV -sT -O -p22,80 192.168.21.140 扫描端口的漏洞…

微服务实战项目-学成在线-项目优化(redis缓存优化)

微服务实战项目-学成在线-项目优化(redis缓存优化) 1 优化需求 视频播放页面用户未登录也可以访问&#xff0c;当用户观看试学课程时需要请求服务端查询数据&#xff0c;接口如下&#xff1a; 1、根据课程id查询课程信息。 2、根据文件id查询视频信息。 这些接口在用户未认…

Java面试——一分钟搞懂限流算法

为什么限流 运营网站&#xff0c;经常会遇到各种挑战&#xff1a;某黑客发起DoS攻击、网络爬虫网页抓取、商品秒杀活动、双十一与618等场景&#xff0c;会使流量突然激增&#xff0c;如果不限制流量的访问就会使系统宕机。 常见的限流算法 1.漏桶算法&#xff08; LEAKY BUC…