条款7:为多态基类声明虚析构函数

文章目录

  • 虚析构函数
  • 声明虚析构函数的情况
  • 继承的情况
  • 总结

虚析构函数

 纪录时间的方法很多,合理的做法是创建一个基类,并为不同的计时方法创建派生类:

class TimeKeeper {
public:TimeKeeper();~TimeKeeper();...
};
class AtomicClock : public TimeKeeper { ... };
class WaterClock : public TimeKeeper { ... };
class WristWatch : public TimeKeeper { ... };TimeKeeper* getTimeKeeper(); // 返回一个指针,指向一个动态分配的派生类对象//…TimeKeeper* ptk = getTimeKeeper(); // 获取动态分配的对象... // 使用它delete ptk; // 释放它以避免资源泄漏

在这里插入图片描述
我们可以看到派生类的析构函数没有执行。

  • 当通过指向具有非虚析构函数的基类的指针删除派生类对象时,结果未定义。
  • 在运行时,对象的派生部分通常不会被销毁,基类部分会销毁,从而导致一个奇怪的“部分销毁”的对象。
     消除这个问题很简单:为基类提供一个虚拟析构函数。然后delete派生类对象就会达到想要的效果。它将销毁整个对象,包括它的所有派生类部分:
class TimeKeeper {
public:TimeKeeper();virtual ~TimeKeeper();...
};
TimeKeeper* ptk = getTimeKeeper();
...
delete ptk; // 现在行为正确了

在这里插入图片描述

声明虚析构函数的情况

 既然将析构函数声明为虚函数可以避免派生类析构函数不执行的问题,那么我们是不是把所有类的析构函数都声明为虚函数就行了呢?答案是不行。当一个类不打算成为基类时,将析构函数设为虚函数通常不是一个好主意。

class Point { // 一个2D的点
public:Point(int xCoord, int yCoord);~Point();
private:int x, y;
};

主要原因如下:
使用虚函数需要而外的,名为vptr(virtual table pointer)的指针,vptr指向一个函数指针数组,称为vtbl (virtual table)。这让这个类的大小凭空多了四个字节的大小。

继承的情况

 标准的string类型不包含虚函数,但有时候我们会写个类继承他。

class SpecialString : public std::string { // 坏主意!string有非虚析构函数};SpecialString* pss = new SpecialString("Impending Doom");
std::string* ps;
...
ps = pss; // SpecialString*  std::string*
...
delete ps; // 未定义的! 实际上派生类部分会被泄露,不会调用SpecialString析构函数

有时你想创造一个抽象类,但却没有任何纯虚函数。怎么办?
解决方案很简单:在想要抽象的类中声明一个纯虚析构函数。

class AWOV { // AWOV = "Abstract w/o Virtuals"
public:virtual ~AWOV() = 0; // 声明纯虚析构函数
};
AWOV::~AWOV() {} // 必须提供纯虚析构函数的定义

总结

  • 多态基类应该声明虚析构函数。如果一个类有虚函数,它应该有一个虚析构函数。
  • 非基类或非多态使用的类不应该声明虚析构函数。

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

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

相关文章

RobotMaster学习——工序导入,参数设置,轨迹生成

目录 引出1.导入工序2.修改刀具其他刀具参数 3.进行工序分配4.设置TCP5.设置工作站6.工序整体导入配置7.进行计算 总结 引出 RobotMaster的操作流程,从导入工序到生产轨迹。 1.导入工序 2.修改刀具 要选择第七把刀具 其他刀具参数 第一把刀具 第二把刀具 第三把刀…

增量式旋转编码器在STM32平台上的应用

背景 旋钮是仪器仪表上一种常见的输入设备,它的内部是一个旋转编码器,知乎上的这篇科普文章对其工作原理做了深入浅出的介绍。 我们公司的功率分析仪的前面板也用到了该类设备,最近前面板的MCU从MSP430切换成了STM32,因此我要将…

linux运维的面试题一

1.linux启动过程 1加电 2加载主板bios设置 3加载多重操作系统启动管理器grub 4加载内核系统到内存当中 5加载配置文件 6加载内核模块 7完成相应的初始化工作和启动相应的服务 8启动系统进程 9出现登录界面 10开机启动完成 2.安装过操作系统吗?怎么安装? 1.小批量设…

Vue+ElementUI+nodejs学生宿舍报修管理系统68ozj

本站是一个B/S模式系统,采用vue框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得学生宿舍信息管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中…

nodejs+vue+ElementUi美发店理发店管理系统q9xc1

本站是一个B/S模式系统,采用vue框架,MYSQL数据库设计开发,充分保证系统的稳定性。系统具有界面清晰、操作简单,功能齐全的特点,使得美发门店管理系统管理工作系统化、规范化。本系统的使用使管理人员从繁重的工作中解脱…

淘宝商品评论API:电商行业的战略资源与制胜之道

在电商行业,数据是金。而其中,用户评论数据更是无价之宝。它不仅仅反映了商品的质量和卖家的服务态度,更是消费者在决策时的关键参考。正因如此,获得淘宝商品评论API的重要性不言而喻。 一、数据背后的无尽宝藏 淘宝,…

MyBatis的动态SQL!!!

一.if和where的使用。 1.首先在UserMapper接口中声明一个方法&#xff1a; package com.by.mapper;import com.by.pojo.User;import java.util.List;/*** <p>Project: mybatis - UserMapper</p>* <p>Powered by scl On 2023-12-22 15:52:05</p>* <…

纯搬运 solidworks 2021卸载方法,怎么完全彻底卸载删除清理干净solidworks 2021各种残留注册表和文件?

纯搬运 solidworks 2021卸载方法&#xff0c;怎么完全彻底卸载删除清理干净solidworks 2021各种残留注册表和文件&#xff1f; 网址&#xff1a; solidworks 2021卸载方法&#xff0c;怎么完全彻底卸载删除清理干净solidworks 2021各种残留注册表和文件&#xff1f; solidworks…

推荐给前端开发的 5 款 Chrome 扩展

工欲善其事&#xff0c;必先利其器。Chrome 可能是前端开发中使用最多的浏览器。在日常开发中&#xff0c;下列几款 Chrome 扩展也许能让你的开发工作事半功倍 &#x1f680; Vue.js devtools ⚙️ vue 官方专为 vue 应用开发的调试工具。 通过使用它&#xff0c;你可以快速查看…

Iceberg:ZOrder的实现及执行流程分析

ZOrder简介 使用Z-Order索引&#xff0c;可以按任意维度对数据进行排序&#xff0c;以获得更加高效且均衡地范围查询。它即可以作为一级索引&#xff0c;直接影响底层数据组织形式&#xff0c;甚至可以取代二索引&#xff08;更加节省内存&#xff0c;吞吐量也理更高&#xff…

SUSE Linux服务器使用zypper安装nginx

SUSE Linux 的云服务器用户&#xff0c;不能yum,安装软件&#xff0c;可通过 zypper 快速安装软件。 使用 root 账号登录 openSUSE 操作系统的云服务器。 执行 zypper service-list 或 zypper sl 命令 列出软件源 安装软件包 执行 zypper search 或 zypper se 命令&#…

【Linux系统基础】(1)Linux基础命令全面详解

在计算机世界中&#xff0c;Linux操作系统以其稳定性、安全性和开源性而受到广大程序员和系统管理员的喜爱。然而&#xff0c;对于初学者来说&#xff0c;Linux的命令行界面可能会显得有些复杂和难以理解。本文将详细介绍一些常用的Linux基础命令&#xff0c;帮助你更好地理解和…