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

先看一段代码:

#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. pl/sql中的record用法

    create or replace procedure pro1(v_in_empno in number) is --定义一个记录数据类型 type my_emp_record is record( ...

  2. Foundation框架 - NSNumber类

    NSNumber类 NSFormatter #import <Foundation/Foundation.h> int main(int argc, const char * argv[] ...

  3. jquery怎样获得父级窗体的大小

    方法例如以下: $(window.parent.window).width() 注意: window能够省略.如:$(parent).width(),parent能够有多级,比方:$(parent.p ...

  4. Gperftools中tcmalloc的简介和使用(转)

    TcMalloc(Thread-CachingMalloc)是google-perftools工具中的一个内存管理库,与标准的glibc库中malloc相比,TcMalloc在内存分配的效率和速度上要 ...

  5. 判断一个字符串是否为合法IP

    输入任意一个字符串,判断是否为合法IP bool IsIPAddress(const char * str){ //先判断形式是否合法, //检查是否只包含点和数字 ; str[i] != '\0'; ...

  6. Android基于UDP的局域网聊天通信

    代码地址如下:http://www.demodashi.com/demo/12057.html 记得把这几点描述好咯:代码实现过程 + 项目文件结构截图 + 演示效果 1. 开发环境 1.1 开发工具 ...

  7. mvc模型绑定问题

    public void AddDesk(x_s_desk x_s_desk) 绑定的到 public void AddDesk(x_s_desk desk) 绑定不到 目前不知道原因 且仅有部分模型需 ...

  8. Nginx通过CORS实现跨域(转)

    如果前端有nginx方向代理,跨域配置在前端反向代理nginx上 要做跨域域名限制 什么是CORS CORS是一个W3C标准,全称是跨域资源共享(Cross-origin resource shari ...

  9. vue 父子组件属性传递

    父子组件属性传递 注意:0.谁被引用,谁就算子组件  1.属性命名最好完全小写,否则需要如下格式转换:myAttr == my-attr 2.引入的vue组件后必须通过 components 注册才能 ...

  10. Linux tomcat安装详解(未完)

    转: http://blog.csdn.net/lcyaiym/article/details/76696192