C++虚析构函数、纯虚析构函数

2023-11-04

虚析构函数
析构函数的工作方式是:最底层的派生类(most derived class)的析构函数最先被调用,然后调用每一个基类的析构函数。
因为在C++中,当一个派生类对象通过使用一个基类指针删除,而这个基类有一个非虚的析构函数,则结果是未定义的。运行时比较有代表性的后果是对象的派生部分不会被销毁。然而,基类部分很可能已被销毁,这就导致了一个古怪的“部分析构”对象,这是一个泄漏资源。排除这个问题非常简单:给基类一个虚析构函数。于是,删除一个派生类对象的时候就有了你所期望的正确行为。将销毁整个对象,包括全部的派生类部分。
但是,一般如果不做基类的类的析构函数一般不声明为虚函数,因为虚函数的实现要求对象携带额外的信息,这些信息用于在运行时确定该对象应该调用哪一个虚函数。典型情况下,这一信息具有一种被称为 vptr(virtual table pointer,虚函数表指针)的指针的形式。vptr 指向一个被称为 vtbl(virtual table,虚函数表)的函数指针数组,每一个包含虚函数的类都关联到 vtbl。当一个对象调用了虚函数,实际的被调用函数通过下面的步骤确定:找到对象的 vptr 指向的 vtbl,然后在 vtbl 中寻找合适的函数指针。这样子会使类所占用的内存增加。
 
定义纯虚析构函数(pure virtual destructor)
 
纯虚成员函数通常没有定义;它们是在抽象类中声明,然后在派生类中实现。比如说下面的例子:
class File //an abstract class
{
public:
  virtual int open(const string & path, int mode=0x666)=0;
  virtual int close()=0;
//...
};
但是,在某些情况下,我们却需要定义一个纯虚成员函数,而不仅仅是声明它。最常见的例子是纯虚析构函数。在声明纯虚析构函数时,不要忘了同时还要定义它。
class File //abstract class
{
public:
  virtual ~File()=0; //declaration of a pure virtual dtor
};
File::~File() {} //definition of dtor
为什么说定义纯虚析构函数是非常重要的
派生类的析构函数会自动调用其基类的析构函数。这个过程是递归的,最终,抽象类的纯虚析构函数也会被调用。
如果纯虚析构函数只被声明而没有定义,那么就会造成运行时(runtime)崩溃。(在很多情况下,这个错误会出现在编译期,但谁也不担保一定会是这样。)纯虚析构函数的哑元实现(dummy implementation,即空实现)能够保证这样的代码的安全性。
class DiskFile : public File
{
public:
  int open(const string & pathname, int mode);
  int close();
  ~DiskFile();
};
File * pf = new DiskFile;
//. . .
delete pf; //OK, ultimately invokes File::~File()
在某些情况下定义其它纯虚成员函数可能也是非常有用的(比如说在调试应用程序以及记录应用程序的日志时)。例如,在一个不应该被调用,但是由于一个缺陷而被调用的基类中,如果有一个纯虚成员函数,那么我们可以为它提供一个定义。
class Abstract
{
public:
  virtual int func()=0;
//..
};
int Abstract::func()
{
std::cerr<<"got called from thread " << thread_id<<
                         "at: "<<gettimeofday()<<std::endl;
}
这样,我们就可以记录所有对纯虚函数的调用,并且还可以定位错误代码;不为纯虚函数提供定义将会导致整个程序无条件地终止。



FROM: http://blog.chinaunix.net/uid-20476365-id-1942463.html

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++虚析构函数、纯虚析构函数 的相关文章

  • 手写android Log 源码(简单版)

    有一天晚上 看了两篇老罗的博客 Android日志系统Logcat源代码简要分析 和 Android日志系统驱动程序Logger源代码分析 于是我就想android10 中 log 是怎么实现的 然后又看了一篇别人的博客 Android10
  • C++类内存分布

    书上类继承相关章节到这里就结束了 这里不妨说下C 内存分布结构 我们来看看编译器是怎么处理类成员内存分布的 特别是在继承 虚函数存在的情况下 工欲善其事 必先利其器 我们先用好Visual Studio工具 像下面这样一步一步来 先选择左侧
  • 构造函数属性为protected或者private时

    在c 中 不仅限于c 一个函数被声明为protected或者private时 那也就意味着不能被外部直接调用了 类的成员函数add 是private class cla private int add int a int b return
  • gcc4.9 编译stdatomic.h 异常

    使用了 include
  • 虚函数在对象中的内存布局

    典型地 C 通过虚函数实现多态性 多态性的定义 无论发送消息的对象属于什么类 他们均发送具有相同形式的消息 对消息的处理方式可能随接受消息的对象而变 具体地说 在某个基类上建立起来的类的层次结构中 可以对任何一个派生类的对象中的同名成员函数
  • C++中虚析构函数的作用

    我们知道 用C 开发的时候 用来做基类的类的析构函数一般都是虚函数 可是 为什么要这样做呢 下面用一个小例子来说明 有下面的两个类 class ClxBase public ClxBase virtual ClxBase virtual v
  • Modern C++的应用,实现golang中的defer

    modern C 实现 golang 的defer 关于RAII的一些思考 defer 的简介 注 没有 golang 语法基础的读者可以看看 反之 可以跳过 golang语法中的defer是什么 defer用来声明一个延迟函数 把这个函数
  • 两个C++编译异常及解决方法-does not name a type和field `XX' has incomplete type

    两个C 编译错误及解决办法 does not name a type和field XX has incomplete type 编译错误一 XX does not name a type 编译错误二 field XX has incompl
  • 23种常用设计模式(C++)

    Part One Methods for constrcting a new object 1 Factory method 我们把简单工厂方法归类到工厂方法中 工厂方法的目的是用来解决具有同一接口 基类 派生类对象的生成问题 尽管可以通过
  • c语言---字符串为什么不能修改内容???字符串常量存放在常量区吗???

    疑惑 1 const修饰的变量都存放在常量区吗 2 字符串常量存放在那 为什么字符型指针 char 指向字符串不能修改其内容 字符串的演变 char p 123456 123456 常量字符串 char static const char
  • C++ 创建共享内存

    共享内存用于实现进程间大量的数据传输 共享内存是在内存中单独开辟一段内存空间 这段内存空间有自己特有的数据结构 包括访问权限 大小和最近访问时间等 1 shmget函数 include
  • 马虎的算式

    标题 马虎的算式 小明是个急性子 上小学的时候经常把老师写在黑板上的题目抄错了 有一次 老师出的题目是 36 x 495 他却给抄成了 396 x 45 但结果却很戏剧性 他的答案竟然是对的 因为 36 495 396 45 17820 类
  • 字符编码与C++

    背景 C 的项目 字符编码是一个大坑 不同平台之间的编码往往不一样 如果不同编码格式用一套字符读取格式读取就会出现乱码 所以本文旨在对字符编码的知识做一个大概的梳理 字符编码定义 计算机是以二进制的形式来存储数据的 它只认识 0 和 1 两
  • 将2个链表交替合并成一个链表

    将带有头结点的2个线性单链表交替有规则的合并成为一个链表 今天做这个的时候 又犯了以前一个愚蠢的错误 对于有些代码 为了方便我就直接复制了 编译器查出来有错 我一直看不出来错误在哪里 那一块我直接就忽略了 代码不敢随便复制 我画个图我认为直
  • c++继承中的内存布局(转)

    今天在网上看到了一篇写得非常好的文章 是有关c 类继承内存布局的 看了之后获益良多 现在转在我自己的博客里面 作为以后复习之用 谈VC 对象模型 美 简 格雷 程化 译 译者前言 一个C 程序员 想要进一步提升技术水平的话 应该多了解一些语
  • C语言中的快速排序库函数

    前言 由于自己的记性一直不好 总是记不住c语言中的快速排序函数 于是自己写下博客来记录一下 快速排序库函数 c语言中的快速排序库函数如下 注意 库函数是在stdlib h头文件中 qsort arr length size t cmp 其中
  • 有些运行符不能重载为友元函数,它们是:=,(),[]和->。

    原因 有人说是因为 C 规定赋值运算符 只能重载为类的非静态成员函数 而不可以重载为类的友元函数 不能重载为类的静态成员应该比较容易理解 因为静态成员函数是属于整个类的 不是属于某个对象的 它只能去操作类静态数据成员 而赋值运算符 是基于对
  • 使用缺省的拷贝构造函数带来的危险性

    我此前另外一篇文章通过类String看拷贝构造函数 赋值函数的作用和区别 对于更深的拷贝构造函数讨论大家可以参见这篇帖子 C 类对象的复制 拷贝构造函数 通过编写类String的拷贝构造函数和赋值函数介绍了一些拷贝构造数 本文着重介绍拷贝构
  • C++ 虚函数表解析

    C 虚函数表解析 陈皓 http blog csdn net haoel 前言 C 中的虚函数的作用主要是实现了多态的机制 关于多态 简而言之就是用父类型别的指针指向其子类的实例 然后通过父类的指针调用实际子类的成员函数 这种技术可以让父类
  • C语言的不完整类型和前置声明

    声明与定义 Declaration and Definition 开始这篇文章之前 我们先弄懂变量的declaration和definition的区别 即变量的声明和定义的区别 一般情况下 我们这样简单的分辨声明与定义的区别 建立存储空间的

随机推荐

  • python 安装pandas

    1 pandas有啥用 pandas 是基于NumPy 的一种工具 该工具是为了解决数据分析任务而创建的 Pandas 纳入了大量库和一些标准的数据模型 提供了高效地操作大型数据集所需的工具 pandas提供了大量能使我们快速便捷地处理数据
  • HarmonyOS扫码服务,应用服务一扫直达打造系统级流量新入口

    二维码如今是移动应用流量入口以及功能实现的重要工具 也是各App的流量入口 是物 人 服务的连接器 通过扫码我们可以更便捷的生活 更高效的进行信息交互 包括信息的发布 信息的获取 在日常扫码过程中 我们也经常会遇到扫码环境暗 二维码污损 模
  • 中国现代服务业发展趋势及十四五战略模式研究报告2021-2027年

    中国现代服务业发展趋势及十四五战略模式研究报告2021 2027年 全新修订 2021年11月 报告价格 纸质版 6500元 电子版 6800元 纸质 电子 7000元 可以优惠 服务形式 文本 电子版 光盘 联 系 人 顾言 撰写单位 鸿
  • Spring Cloud Alibaba Dubbo

    Spring Cloud Alibaba Dubbo 为什么 是什么 怎么做 为什么 单体应用 单体服务经过长期的迭代更新 逐渐走向代码臃肿 高耦合 这显然与我们软件开发设计理念高内聚 低耦合背道而驰 从而难以维护 市场需求也在逐渐要求服务
  • 惠普360 g5服务器系统如何做阵列,求HP DL360G5 2.5服务器,基于windows server 2008系统安装RAID 1方法...

    一 在BIOS中打开RAID功能 安装好SATA硬盘之后 就要进入BIOS中打开南桥芯片的RAID功能 具体方法是 进入BIOS设置程序的 OnChip IDE Device 窗口 找到一个名为 SATA Mode 的选项 将它设置为 RA
  • glsl中uniform,attribute和varying详解

    openGL系列文章目录 文章目录 openGL系列文章目录 uniform attribute varying 参考 uniform 要想渲染一个场景以使它看起来是3D 的 需要构建适当的变换矩阵 并将它们应用于模型的每个顶点 在顶点着色
  • 龙斗士显示网络和服务器,龙斗士热点问题_百田网帮助中心

    战斗类问题 7 怎样组队或离开队伍 你好 小冒险家如果想要组织队伍一起去冒险 可以在页面右下方打开 组队 图标 选择 创建组队 创建一支队伍 小冒险家成功建立队伍后 打开 组队 图标 选择 邀请队友 就能邀请朋友加入队伍了 如果要离开队伍
  • 基于HTML和CSS完成京东页面的制作

    首先打开京东页面分析页面元素 由图可把整个页面分为4个部分 分别为top顶部部分 tip提示部分 mid中间部分 foot底部部分 然后编写每一部分的代码 边写边测试结果 防止一步错步步错 代码如下 HTML部分 div class top
  • C#新语法

    本文章是我听B站杨中科的所做的笔记 杨中科B站视频链接 NET 6教程 Net Core 2022视频教程 杨中科主讲 哔哩哔哩 bilibili 说明 1 C 8 0 C 9 0和C 10 0中增加了很多的新语法 这里讲解常用 重点的新语
  • 解决Ajax获取文本数据为空的问题

    今天学习了Ajax 想自己封装一个函数 结果第一步就难住了 我无论怎样都获取不到文本文件或者Json里的值 难受的找了半天bug 百度了好久 不是很懂后台代码 用文本文件保存的数据 找不到适合我的解决方案 关键是控制台没有报错 就是aler
  • Unity ToLua框架整理(一) C#和lua函数调用

    记录下 方便自己用 代码已加注释 就不多说了 应该能看懂 1 C 调用Lua代码 Lua代码 lua代码放在tolua自带的lua目录 建议下个LuaBuilder配合VS2017使用 local GameObject UnityEngin
  • Open3D 读取、保存、显示点云

    目录 一 主要函数 1 读取点云 2 保存点云 3 显示点云 4 Open3D支持的点云格式 5 输出点云信息 二 代码实现 包括读取txt格式 三 结果展示 四 可视化两个点云 五 给点云随机赋色 六 显示点云自身的颜色 一 主要函数 1
  • 基于SpringBoot+VUE的考试题库刷题系统

    全网粉丝20W csdn特邀作者 博客专家 CSDN新星计划导师 java领域优质创作者 博客之星 掘金 华为云 阿里云 InfoQ等平台优质作者 专注于Java技术领域和毕业项目实战 文末获取项目下载方式 一 项目背景介绍 在现代教育领域
  • TypeScript 中 any、unknown、never 和 void 有什么区别?

    一 unknown 未知类型 unknown 未知类型是typescript 3 0 中引入的新类型 1 1 所有类型的字面量都可以分配给unknown类型 unknown未知类型 代表变量类型未知 也就是可能为任意类型 所以 所有类型的字
  • Java集合的深拷贝

    package test01 import java io ByteArrayInputStream import java io ByteArrayOutputStream import java io IOException impor
  • OpenCV 2.4+ C++ 人脸识别

    机器学习 机器学习的目的是把数据转换成信息 机器学习通过从数据里提取规则或模式来把数据转成信息 人脸识别 人脸识别通过级联分类器对特征的分级筛选来确定是否是人脸 每个节点的正确识别率很高 但正确拒绝率很低 任一节点判断没有人脸特征则结束运算
  • 浪潮服务器通过IPMI装系统

    1 登陆BMC挂载虚拟光驱 1 使用浏览器打开 ipmi 的 Web 登录界面 默认用户名 密码 admin admin 登录 2 登录后选择 远程控制 下的 控制台重定向 选择 Java 控制台 开启 Java 3 点击media加载光驱
  • 通过selenium进入iframe框架、alert弹窗点击操作

    以菜鸟实验 driver switch to frame iframeResult 进入frame 通过frame的id值 driver find element By XPATH html body input get attribute
  • 频偏计算方式

    1 我们描述频偏的时候一般是以ppm作为单位来描述的 ppm是百万分之一的意思也就是10 6 2 如何计算频偏 假如我们有一个晶振 它的频率标值是12MHZ 但是我们测试到的是11 99998MHZ 那么Foffset 12 11 9999
  • C++虚析构函数、纯虚析构函数

    虚析构函数 析构函数的工作方式是 最底层的派生类 most derived class 的析构函数最先被调用 然后调用每一个基类的析构函数 因为在C 中 当一个派生类对象通过使用一个基类指针删除 而这个基类有一个非虚的析构函数 则结果是未定