zoukankan      html  css  js  c++  java
  • 虚析构函数

    在看《Essential C++》的时候,碰到一句话,不是很明白,今天在看《程序员面试宝典》的时候,又看到了这个问题,记录下来。
    《Essential C++》中写到

    根据一般规则,凡基类定义有一个(或多个)虚函数,应该要将其析构函数声明为virtual
    

    看下面的代码

    #include "pch.h"
    #include <iostream>
    using namespace std;
    
    class CBase
    {
    public:
    	~CBase()
    	{
    
    	}
    };
    
    class CChild : public CBase
    {
    public:
    	~CChild()
    	{
    
    	}
    };
    
    int main()
    {
    	CChild c;
    
    	return 0;
    }
    

    上面代码在运行时,由于在生成CChlid对象c时,实际上在调用CChild类的构造函数之前必须首先调用其基类CBase的构造函数,所以当撤销c时,也会在调用CChild类析构函数之后,调用CBase类的析构函数(析构函数调用顺序和构造函数相反)。也就是说,无论析构函数是不是虚析构函数,派生类对象被撤销时,肯定会依次调用其基类的析构函数。
    那么为什么需要虚析构函数那?
    因为多态的存在!

    int main()
    {
    	CChild c;
    
    	CBase* pBase;
    	pBase = &c;
    	return 0;
    }
    
    

    考虑上面的代码,在pBase指针被撤销时,调用的是CBase的析构函数还是CChild的析构函数那?显然是CBase的(静态联编)析构函数,但如果把CBase类的析构函数改为virtual型,当pBase指针被撤销时,就会先调用CChild类析构函数,再调用CBase类的析构函数。
    看下面的两份代码

    #include "pch.h"
    #include <iostream>
    using namespace std;
    
    class CBase
    {
    public:
    	~CBase()
    	{
    		cout << "这是CBase类的析构函数" << endl;
    	}
    };
    
    class CChild : public CBase
    {
    public:
    	~CChild()
    	{
    		cout << "这是CChild类的析构函数" << endl;
    	}
    };
    
    int main()
    {
    	//CChild c;
    
    	CBase* pBase;
    	pBase = new CChild();
    	delete pBase;
    	return 0;
    }
    

    当pBase被撤销时,因为CBase类的析构函数不是虚函数,non-vitrual函数在编译时便已完成解析,根据该对象被调用时的类型来判断,所以只会调用CBase类自己的析构函数。从而不会释放CChild占据的内存,造成内存泄漏。
    再看这份代码

    #include "pch.h"
    #include <iostream>
    using namespace std;
    
    class CBase
    {
    public:
    	virtual ~CBase()
    	{
    		cout << "这是CBase类的析构函数" << endl;
    	}
    };
    
    class CChild : public CBase
    {
    public:
    	~CChild()
    	{
    		cout << "这是CChild类的析构函数" << endl;
    	}
    };
    
    int main()
    {
    	//CChild c;
    
    	CBase* pBase;
    	pBase = new CChild();
    	delete pBase;
    	return 0;
    }
    
    

    由于CBase类的析构函数是虚函数,当pBase指针被撤销时,就会先调用CChild类的析构函数,再调用CBase类的析构函数。这样就不会出现由于析构函数未被调用而导致的内存泄漏。

  • 相关阅读:
    Java 到底是值传递还是引用传递
    Java.lang.Comparable接口和Java.util.Comparator接口的区别
    线程安全和线程不安全的区别
    剑指offer第五天
    快速排序法
    剑指offer第四天
    length()方法,length属性和size()的方法的区别
    linux 下创建管理员权限账户
    Centos6.5 rpm方式指定目录安装JDK
    阿里云云服务器硬盘分区及挂载
  • 原文地址:https://www.cnblogs.com/Manual-Linux/p/11093929.html
Copyright © 2011-2022 走看看