为多态基类声明一个虚析构函数(Effective C++_7)

本文探讨了C++中声明虚析构函数的重要性,特别是在多态基类中的应用。未声明虚析构函数可能导致只调用基类析构函数,忽略派生类的析构,从而引发内存泄漏。只有具有virtual函数的多态基类才应声明虚析构函数,以确保正确销毁所有子对象。同时,文章提到了纯虚析构函数的使用场景和不应声明虚析构函数的情况。最后,强调非为多态设计的类如STL容器和string不应有虚析构函数。
摘要由CSDN通过智能技术生成

一、声明虚析构函数的原因

(1)先考虑没有声明虚析构函数的代码:

#include <iostream>
using namespace std;

class Base{
public:
    Base(int x,int y):a(x),b(y){
        cout<<"Base Construction"<<endl;
    }
    virtual void display()=0;
     ~Base(){
        cout<<"Base Destuction"<<endl;
    }
private:
    int a;
    int b;
};


class D1:public Base{
public:
    D1(int x,int y,int z):Base(x,y),c(z){
        cout<<"D1 Construction"<<endl;
    }
     void display(){
        cout<<"D1 Class"<<endl;
    }
     ~D1(){
         cout<<"D1 Destuction"<<endl;
     }
private:
    int c;
};


class D2:public D1{
public:
    D2(int x,int y,int z,int w):D1(x,y,z),d(w){
        cout<<"D2 Construction"<<endl;
    }
    ~D2(){
        cout<<"D2 Destuction"<<endl;
    }
    virtual void display(){
        cout<<"D2 Class"<<endl;
    }
private:
    int d;
};


int main(){ 
    Base* p=new D1(1,2,3);
    p->display();
    delete p;
    return 0;
}

其结果是:

Base Construction
D1 Construction
D1 Class
Base Destuction
请按任意键继续. . .

这里没有把析构函数声明为虚析构函数,那么,销毁对象时,只调用了基类的析构函数;假如,把基类的析构函数声明为虚析构函数,那么就会有下面的结果:

Base Construction
D1 Construction
D1 Class
D1 Destuction
Base Destuction
请按任意键继续. . 

当派生类的对象从内存中撤销时一般先调用派生类的析构函数,然后再调用基类的析构函数。但是,如果用new运算符建立了临时对象,若基类中有析构函数,并且定义了一个指向该基类的指针变量。在程序用带指针参数的delete运算符撤销对象时,会发生一个情况:系统会只执行基类的析构函数,而不执行派生类的析构函数;当声明为虚析构函数后,则会调用所有的析构函数,不会造成内存泄漏


二、何时声明为虚析构函数
(1)并不是所有c++类都应该将析构函数设置为virtual。只有具有virtual函数的多态基类(或者其它想当base class的类)才应该将析构函数设置为virtual,对于普通的类则无必要

因为虚函数的实现要求对象携带额外信息,也就是维护一个指向虚函数表的指针vfptr(virtual table pointer),vfptr指向虚函数表vtbl(virtual table)。当有虚函数时,声明一个对象时,对象的首地址会存储vfptr指针,而无虚函数时,则没有这样的指针;那么这会给对象带来多余的负担,所以对于非多态基类,没必要将析构函数声明为virtual以带来额外负担。

(2)纯虚析构函数:如果某个class只希望作为base class(不希望被实例化),但是又没有一个纯虚函数,而base class应该有一个virtual析构函数,那么此时就可以将析构函数设置为纯虚函数。必须为纯虚析构函数提供定义,否则会出现Link错误;

class Base{
virtual ~Base()=0;
}
Base::~Base(){};

(3)如果一个类的不是设计作为基类来使用,或不是为了具备多态性,就不应该声明virtual析构函数


三、基类并非均是为了多态

(1)标准库中的STL容器和string类,不是设计作为基类使用的,它们均没有虚析构函数,不要继承它们
(2)比如Uncopyable的设计是为了明确拒绝赋值,而不是为了设计成多态,所以也不需要虚析构函数


参考:Effective C++ 3rd(侯捷译)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值