C++将析构函数定义成virtual的真正原因

C++中基类的析构函数为什么要用virtual虚析构函数 基类的析构函数添加virtual关键字 阅读详情
 

1. 一般来说,如果一个类要被另外一个类继承,而且用其指针指向其子类对象时,如题目中的A* d = new B();(假定A是基类,B是从A继承而来的派生类),那么其(A类)析构函数必须是虚的,否则在delete d时,B类的析构函数将不会被调用,因而会产生内存泄漏和异常;

2. 在构造一个类的对象时,先构造其基类子对象,即调用其基类的构造函数,然后调用本类的构造函数;销毁对象时,先调用本类的析构函数,然后再调用其基类的构造函数;

3. 题目给出的代码是可以编译的,但会出现运行时错误。错误出现在delete d;这一句。为讨论方便,我们不妨将A类和B类改写如下:

class A
{
public:
    int a;
    ~A()
    {
        cout << "A::~A" << endl;
    }
};

class B : public A
{
public:
    int b;
    virtual ~B()
    {
        cout << "B::~B" << endl;
    }
};
那么A* d = new B();这一句的左边所产生B的对象的内存结构如下:

而A对象的内存结构如下:

可见d只能找到a和A类的析构函数,而无法找到B对象的析构函数,所以当delete d;的时候,B对象所占用的内存就此被泄漏掉了,也从而产生了异常。

 

如果将A类的析构函数设为虚的,那么A类对象的内存结构将为:

 

B类对象的内存结构为:

此时通过A* d = new B();,A对象的内存结构中的vfptr,即虚函数表指针,就是B对象的vfptr(B对象的vfptr被bitwise copy,即浅拷贝到A对象的vfptr。如B是从A虚继承而来的,则需要加一个offset,情况要更复杂,见

http://blog.youkuaiyun.com/pathuang68/archive/2009/04/24/4105902.aspx),因此,A对象的vfptr所指向的是B对象的虚函数表,而B的析构函数位于书函数表0的位置,因此,这样就可以通过A类对象的指针d,找到B类对象的析构函数,从而在delete d;时,可以销毁B对象,而不会产生内存泄漏和异常。


事实上,该题目只要将A中的析构函数设成虚的,B类中的析构函数前面的virtual关键字不管是否存在,其析构函数也一定是虚的,C类同此道理。因此,得到结论就是,只要能够保证继承关系中最高的基类的析构函数是虚的,那么就不会产生前面所谈及的问题。这就是为什么在想使用多态特性的时候,需要将基类的析构函数设成虚的真正原因。

基类的析构函数不加virtual引起的异常 #include <iostream> using namespace std; class Animal{ public: static int number; virtual void printCount()=0; Animal(){ ++Animal::number; } virtual ~Animal(){ //错误... 阅读详情

相关推荐

亲测:C++析构函数定义成virtual函数的必要性

关于为什么要将析构函数定义成虚函数,为了加深印象,写了个小测试代码对比了一下: #include &lt;iostream&gt; using namespace std; class Base{ public:     Base()     {         cout &lt;&lt; "Constructor of Base" &lt;&lt;endl;     }      virtu...

Reminder的博客 462

C++析构函数后加上virtual的原因

C++析构函数加上virtual是为了防止内存泄漏。 用在C++实现多态的时候,其基类要加virtual。 原因跟动态绑定有关,大家都知道,多态是通过虚函数实现的,而虚函数又是通过动态绑定实现的。 先举个例子: class Base { public: virtual void function() { cout<<"this is Base's function"<<e

ZJE 5763

Cadence ADE实战:1GHz VCO相位噪声仿真全流程(附PSS/Pnoise避坑指南)

本文详细介绍了在Cadence ADE环境中对1GHz VCO进行相位噪声仿真的完整流程。重点剖析了PSS(周期性稳态分析)和Pnoise(周期性噪声分析)两大核心引擎的关键参数设置与避坑指南,帮助射频与模拟IC设计者准确评估VCO性能,解决仿真不收敛、结果异常等常见问题。

rock5的博客 671

c++ 析构函数为什么要加virtual

这是因为当用基类引用派生类的时候,如果此时对基类进行delete操作,对于没有虚函数析构函数,那么只会调用基类的析构函数,而对派生类的析构函数不会进行析构 相关文章转载:http://www.cnblogs.com/lixiaohui-ambition/archive/2012/07/13/2589716.html

gonaYet的博客 498

华为2022硬件逻辑笔试题

单选题(每题两分) 1.以下关于过程赋值的描述,不正确的是() A在非阻塞性过程赋值中,使用赋值符号“< =” B赋值操作符是“=”的过程赋值是阻塞性过程赋值 C在非阻塞性过程赋值中,对目标的赋值是非阻塞的(因为时延),但可预定在将来某个时间步发生(根据时延:如果是0时延,那么在当前时间步结束) D非阻塞性过程赋值在其后所有语句执行前执行 解:D 2.芯片的功耗和下列哪种不强相关_____________。 A资源利用率 B核电压 C组合逻辑级数 D翻转率 解:A 3.下列说

weixin_44072819的博客 1万+

DLMS-Blue-Book蓝皮书—曲线类

attribute_index 1 指的是第 1 个属性(即 logical_name),attribute_index 2 指的是第 2 个属性,等等;如果其他“曲线通用类”对象捕获了这个缓冲区,它们的缓冲区也将被清空,以保证它们的缓冲区条目是同质的。如果捕获对象是曲线通用类的缓冲区,则 data_index 标识缓冲区(即列)中的捕获对象(即内部曲线通用类中的列);如果曲线通用类已排序,则调用捕获方法将把新条目存储在缓冲区中的适当位置,移动所有后续条目,并可能丢失最不相关的条目。

一个bug是bug,多个bug能work 1454

为什么析构函数要声明成virtual

(zz)为什么析构函数要声明成virtual   2011-03-08 15:43:00|  分类: reproduct|字号 订阅 为什么析构函数要声明成virtual呢? 因为,如果delete一个基类的指针时, 如果它指向的是一个子类的对象,那么析构函数不为虚就会导致无法调用子类析构函数,从而导致资源泄露。 当然,另一种做法是将基类析

qiangwa0的专栏 4059

一步步指导:在Chrome中安装Vue插件vue-devtools

Vue.js是现代Web开发中最流行的前端框架之一,它以其轻量级、高性能和易于理解的设计理念受到开发者的喜爱。为了更高效地开发和调试Vue应用,Vue.js官方提供了一个强大的开发工具——vue-devtools。

小透明的博客 5619

c++语言基础:析构函数为什么要用virtual,static和const

c++基础

qq_51046087的博客 1565

通俗易懂的图解二叉搜索树、AVL树和红黑树

搜索是一种很常见的需求,当数据较多时,如何找到目标对象时,即需要搜索查找。 那么如何快速找到目标呢,最朴素的思想就是暴力查找,一个一个对比。 显然,当数据量增大时,我们需要优化查找方法获取更快的查找速度,我们可以通过维护一个有序数组,从而实现二分查找,查找速度从O(n)降为O(longn)。 但是数组并不便于插入和删除,链表便成为了最好的选择。 既然是采用二分查找,那么不如直接按照查找的步骤维护一种数据结构,于是二叉搜索树出现了。 二叉搜索树的性质为: 若左子树不为空,则左子树上所有节点值都小于根结点值;

暗色光的博客 758

YOLO26 多任务统一架构:检测 / 分割 / 姿态 / OBB 设计

YOLO26提出了一种多任务统一架构,整合了目标检测、实例分割、姿态估计和旋转框检测(OBB)四大计算机视觉任务。该架构采用共享Backbone和Neck的设计,配合轻量级任务特定Head,解决了传统方法中多模型并行带来的高开发成本、大内存占用和低推理效率问题。核心设计包括:1)共享特征提取层实现参数复用;2)模块化Head结构支持灵活任务组合;3)统一接口实现单模型多任务处理。实验表明,该架构在保持各任务性能的同时显著提升了系统效率,为多任务视觉系统提供了新的实现范式。

一键难忘的博客 705

C++将析构函数定义成virtual的原因

疑问:为什么在C++的实际使用中继承子类的虚构函数有的时候需要添加virtual有时候不需要添加virutal

静夜思 963

车载ECU底软测试:方法与技术的深度解析

底软是运行在 ECU 硬件平台上的基础软件,它为上层应用程序提供了硬件驱动、操作系统服务、通信协议栈等功能。底软的主要功能包括:硬件驱动:负责与 ECU 的各种硬件外设进行通信和控制,如 GPIO、UART、SPI、CAN 等。操作系统服务:提供任务调度、内存管理、中断处理等功能,确保系统的实时性和稳定性。通信协议栈:实现 ECU 与其他 ECU 或外部设备之间的通信,如 CAN、LIN、FlexRay 等。诊断服务:负责对 ECU 的故障进行诊断和处理,并将故障信息存储在故障码存储器中。

天赐好车的博客 1429

C++析构函数前加上virtual的原因

class A {     public:         virtual void print(){cout&lt;&lt;"This is A"&lt;&lt;endl;} }; class B : public A {     public:     void print(){cout&lt;&lt;"This is B"&lt;&lt;endl;} } 虚函数:指向基类...

try_again_later的博客 3627

[AHK]获取通达信软件上的股票代码

PC上的股票交易软件的自动止损、自动下单等功能比较弱,不如期货交易软件。 自力更生,程序员都是自己打造工具。 根据IPO模型(Input 输入,Process处理,Output输出),为了方便自动化首先要获取当前交易软件上浏览的股票代码。 截图再OCR显然太麻烦,通过Winspy工具查看下交易软件自带功能的消息号(33780),大家记住这个号码! 下面在用AutoHotkey作为变成语...

liuyukuan的专栏 1万+

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

C++中的虚析构函数

Cpp中的虚析构函数 1.虚析构函数的作用:为了避免内存泄漏,而且是当子类中会有指针成员变量时才会使用到。即虚析构函数使得在删除指向子类对象的基类指针时,可以调用子类的析构函数来实现释放子类中堆内存的目的,从而防止内存泄漏。 2.C++中开发中,基类中的析构函数一般都是虚函数,如下面的例子: #include <iostream> using namespace st...

CurryCoder的个人博客 1万+

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C++将析构函数为啥需要定义成virtual

一般来说,如果一个类要被另外一个类继承,而且用其指针指向其子类对象时,如题目中的A* d = new B();(假定A是基类,B是从A继承而来的派生类),那么其(A类)析构函数必须是虚的,否则在delete d时,B类的析构函数将不会被调用,因而会产生内存泄漏和异常; 在构造一个类的对象时,先构造其基类子对象,即调用其基类的构造函数,然后调用本类的构造函数;销毁对象时,先调用本类的析构函数,然后再...

u013321328的专栏 371

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C++ 虚拟析构函数 (virtual destructor)

C++ 虚拟析构函数 (virtual destructor). 虚拟析构函数的用法以及使用场景.

我是小白呀的博客 7873

C++ virtual 析构函数

<br />copy自:http://zxjgoodboy.blog.sohu.com/61482463.html<br />在此基础上稍作修改<br /> <br />C++中虚析构函数的作用<br />我们知道,用C++开发的时候,用来做基类的类的析构函数一般都是虚函数。可是,为什么要这样做呢?下面用一个小例子来说明: <br />有下面的两个类:<br />#include <iostream> using namespace std; class ClxBase { public:

aore2010的专栏 9625

C++ 基类和派生类的virtual虚析构函数

virtual虚函数与C++的多态息息相关,C++中基类采用virtual虚析构函数主要目的是为了防止潜在的内存泄漏。 具体地说,如果派生类中申请了内存空间,并在其析构函数中对这些内存空间进行释放。假设基类中采用的是非虚析构函数,当删除基类指针指向的派生类对象时就不会触发动态绑定,因而只会调用基类的析构函数,而不会调用派生类的析构函数。那么在这种情况下,派生类中申请的空间就得不到释放从而产生内存...

hanzhen7541的博客 2841

C++ 中关于virtual析构函数

尽量将析构函数定义为virtual。

zjc156m的专栏 2978

C++学习-基类析构函数必须使用virtual原因记录

C++中,为了避免派生类被基类指针指向并释放时,派生类的析构函数不会被调用所产生的内存泄漏问题,析构函数一般使用virtual修饰 Women.hpp class BaseClass { public: virtual ~ BaseClass(); //1.这里不使用virtual,在子类释放时就会发生内存泄漏 virtual void sayWhatWrongWithYou();...

CaicaiNo.1 342

[Effective C++]条款7 virtual析构函数

说到多态, 我们应当非常了解其运行时绑定的机制, 简单来说就是我们可以在任何时候根据用户的需求将基类绑定为不同的派生类, 用相同的操作实现不同的效果, 这其中virtual函数起到了至关重要的作用, 每一个含有虚函数的类都会维护一个虚表, 以此实现基类到派生类的动态绑定.

tianmu_sama的博客 878
上一篇: 对c++的多态性的一个疑问
下一篇: QT API的继承类图(看QT API的前提)
jacqueslim
博客等级 码龄16年 12粉丝 19原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值