【C++学习】 C++ 虚析构(virtual destructor)浅析

【C++学习】C++ 虚析构(virtual destructor)浅析

先来看一段简单的代码(main.cpp):

#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;
}

运行结果为:
这里写图片描述

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

这里写图片描述

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

那为什么加了virtual就会调用子类的析构函数呢?这是本文的主题。
首先要理解几个概念:
1,在没有加virtual的时候,这个继承体系没有任何虚函数,所以CSon,CBase均不含虚函数表。

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

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中会自动递归调用父类的析构函数,所以全部资源释放完成。

在命令行里通过如下命令来查看CSon对象的内存布局:

cl main.cpp /d1reportSingleClassLayoutCSon

具体操作方法可以查看我之前的文章—–【C++学习】 VS2012 使用命令行选项查看对象的内存布局
其内存布局如下图所示:
这里写图片描述
可以看到,由于父类的析构函数为virtual,则会有虚表,虚表中子类的析构函数覆盖了父类的析构函数,这个是通过编译器来处理的,因为子类的析构函数名跟父类不一样,编译器做了处理,让其覆盖父类的析构函数。不知道这样理解是否准确,如有问题,欢迎大家指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值