注意:本文仅为个人理解,可能有误!

先看一段代码:

#include <iostream>
using namespace std; class CBase{
public:
CBase()
{
cout<<"CBase construct ... "<<endl;
}
virtual ~CBase()
{
cout<<"CBase destructor ... "<<endl;
}
}; class CSon : public CBase{
public:
CSon(){
cout<<"CSon construct ... "<<endl;
}
~CSon(){
cout<<"CSon destructor ... "<<endl;
}
}; void test()
{
CBase* pObj = new CSon();
delete pObj;
} int main(int argc,char* argv[])
{
test();
return 0;
}

上面这段代码,输出:

CBase construct ...

CSon construct ...

CSon destructor ...

CBase destructor ...

大家都能理解,而将virtual ~CBase() 的virtual 去掉, 将输出:

CBase construct ...

CSon construct ...

CBase destructor ...

大家将看到,子类的析构函数没有被调用。

 

那为什么加了virtual就会调用子类的析构函数呢?这是本文的主题。

 

首先要理解几个概念:

0,在没有加virtual的时候,这个继承体系没有任何虚函数,所以CSon,CBase均不含虚函数表。

1,子类构造函数/析构函数会自动调用父类的构造/析构函数(编译期决定);

2,编译期的常识:

CBase* pObj = new CSon(); 

这句相当于

CSon* pTmp = new CSon();

CBase* pObj = (CBase*)pTmp; 

前一句中编译器是直接调用CSon::CSon()返回位pTmp,pTmp赋值给pObj。因而生成的pObj实际上是CSon对象,但pObj的类型被记录为CBase类型。

delete pObj;  

delete时编译器只知道这个pObj是CBase类型 。

情况一,在CBase的析构函数为非virtual时:

编译器在编译“delete pObj;” 时根据pObj的类型是CBase调用CBase::~CBase(),不会调用子类析构函数。

情况二,在CBase的析构函数为virtual时:

此时继承体系中有一个虚函数表,这个时候,编译器就不会直接调用CBase::~CBase(),而是调用call pObj->pvtable-> vtable[0],又pObj这个对象实际上是CSon对象,所以调用流程如下:

delete pObj; –> call pObj->pvtable-> vtable[0] –> CSon::~CSon()

而在CSon::~CSon中会自动递归调用父类的析构函数,所以全部资源释放完成。

 

关于动态绑定部分,可以参见如下两张图:

1,CBase初始化完毕:

2,CSon初始化完毕:

C++ 虚析构(virtual destructor)原理的更多相关文章

  1. [C++] Virtual Destructor(虚析构函数)

    Without Virtual Destructor(虚析构函数) class A{ public: ; A() { cout <<"A()..."<< e ...

  2. C++中虚析构的作用

    为了当用一个基类的指针删除一个派生类的对象时,派生类的析构函数会被调用. 基本概念: 析构函数是用来回收对象的: 虚析构函数是析构函数的一种: 基类是一类对象共有属性的抽象.比如,猫和狗都是动物,都会 ...

  3. C++ - 复制(copy) 和 虚复制(virtual copy) 的 区别

    复制(copy) 和 虚复制(virtual copy) 的 区别 本文地址: http://blog.csdn.net/caroline_wendy/article/details/16120397 ...

  4. C++的虚析构

    最近准备复习一遍所有的知识点,先从基础开始做起,用几分钟写个继承和析构吧. 父类为A,子类为B,代码如下: class A { public: A() { cout << "构造 ...

  5. C++虚函数的工作原理

    静态绑定与动态绑定 讨论静态绑定与动态绑定,首先需要理解的是绑定,何为绑定?函数调用与函数本身的关联,以及成员访问与变量内存地址间的关系,称为绑定. 理解了绑定后再理解静态与动态. 静态绑定:指在程序 ...

  6. C++中虚函数的作用和虚函数的工作原理

    1 C++中虚函数的作用和多态 虚函数: 实现类的多态性 关键字:虚函数:虚函数的作用:多态性:多态公有继承:动态联编 C++中的虚函数的作用主要是实现了多态的机制.基类定义虚函数,子类可以重写该函数 ...

  7. C++——虚析构

    目的: //只执行了 父类的析构函数//向通过父类指针 把 所有的子类对象的析构函数 都执行一遍//向通过父类指针 释放所有的子类资源 方法:在父类的析构函数前+virtual关键字 #define ...

  8. C++ //虚析构和纯虚析构

    1 //虚析构和纯虚析构 2 3 #include <iostream> 4 #include <string> 5 using namespace std; 6 7 clas ...

  9. Delphi之静态方法,虚方法virtual,动态dynamic,抽象abstract,消息

    Delphi之静态方法,虚方法virtual,动态dynamic,抽象abstract,消息 http://www.cnblogs.com/zhwx/archive/2012/08/28/266055 ...

随机推荐

  1. 计算两个经纬度之间的距离(python算法)

    EARTH_REDIUS = 6378.137 def rad(d): return d * pi / 180.0 def getDistance(lat1, lng1, lat2, lng2): r ...

  2. 代码这样写更优雅(Python 版)(转载)

    转载:https://mp.weixin.qq.com/s?timestamp=1498528588&src=3&ver=1&signature=DfFeOFPXy44ObCM ...

  3. maven 插件之 AutoConfig 工具使用笔记

    AutoConfig 是一款 maven 插件,主要用于 Maven 项目打包使用.在我们的工作中,会将自己写的代码打成 jar 包或者 war 包发布到各种环境上.一般地,不用的环境所使用的数据库. ...

  4. 使用 Apple Configurator 2 获取ipa文件

    如今很多人想要获取到App Store上的包却苦于无奈,先在要把App Store上的包载下来获取ipa,最直接的就是从手机设备上导出了,但是手机必须要9.0以下才可以导出,鄙人手中正好有公司的测试机 ...

  5. 图解avaScript中this指向(超透彻)

    一个图讲清楚JavaScript中this指向: 说明: (1)严格模式下,禁止this关键字指向全局对象会报错. (2)闭包中的this对象具有全局性,因此通常指向window.  (3)优先级:n ...

  6. 一个下载git库代码的脚本

    由于每日构建需求, 须要用脚本下载代码, 实现自己主动化编译, 这个脚本是整个系统的一小块功能 #!/bin/bash #@author Liuyang #@date 2015-06-23 funct ...

  7. lucene 多索引目录搜索实现方法

    http://akululu.iteye.com/blog/314130 多索引目录就是要在多个索引目录的中进行比较搜索,类似概念在SQL中就是select * from TableA union s ...

  8. Android编程之Fragment使用动画造成Unknown animation name: objectAnimator异常

    在为Fragment做切换动画.启动后遇到了一个异常: Caused by: java.lang.RuntimeException: Unknown animation name: objectAni ...

  9. delphi中检测局域网ip能够ping通模块

    // 函数PingHost用于ping目标IP是否连通 // uses winsock    在uses中加入  winsock // 用法:  if PingHost(edit2.Text) the ...

  10. Atitit.java swing打印功能 api  attilax总结

    Atitit.java swing打印功能 api  attilax总结 1. 打印方式有三种:2 1.1. 一是不经过任何修改,直接调用javascript中的window.print()打印.2 ...