C++基础---虚析构函数与纯虚析构函数

1. 虚析构函数与纯虚析构函数

1.1 虚析构函数与纯虚析构函数的定义

  • 虚析构函数:为了解决基类的指针指向派生类对象,并用基类的指针删除派生类对象
  • 虚析构函数:当且仅当类里包含至少一个虚函数的时候才去声明虚析构函数,无故的声明虚析构函数和永远不去声明一样是错误的;

    class <类名>
    {
    virtual ~<类名>();
    …
    };
    即:virtual ~A();
  • 纯虚析构函数:抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以方法很简单,在想要成为抽象类的类里声明一个纯虚析构函数;

    class <类名>
    {
    virtual ~<类名>() = 0;
    …
    };
    即:virtual ~A() = 0;

    注:如果某个类不包含虚函数,那一般是表示它将不作为一个基类来使用。当一个类不准备作为基类使用时,使析构函数为虚一般是个坏主意。因为它会为类增加一个虚函数表,使得对象的体积翻倍,还有可能降低其可移植性。

1.2 带有虚函数功能的类需要一个虚析构函数的原因

  • 如果一个类有虚函数功能,它经常作为一个基类使用;
  • 如果它是一个基类,它的派生类经常使用new来分配;
  • 如果一个派生类对象使用new来分配,并且通过一个指向它的基类的指针来控制,那么它经常通过一个指向它的基类的指针来删除它;
    注:
    (1)如果基类没有虚析构函数,结果将是不确定的,实际发生时,派生类的析构函数永远不会被调用。
    (2)如果基类有虚析构函数的话,最底层的派生类的析构函数最先被调用,然后各个基类的析构函数被调用。

1.3 虚析构函数的注意点

  • 由于析构函数不允许有参数,因此它不可能实现重载,那么一个类就只能有一个虚析构函数;
  • 只要基类的析构函数被声明为虚函数,则派生类的析构函数无论说明与否,都自然是析构函数;
  • 如果基类中定义了虚函数,析构函数也应说明为虚函数,这样对内存的回收更准确些;
    注:在C++中虚构造函数是不存在的,因此也无法声明。

1.4 虚析构函数的实例

  • (1)在带有虚函数的基类中定义普通析构函数

    
    #include <iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A(){cout<<"A()..."<<endl;}
        ~A(){cout<<"~A()..."<<endl;}
    
    public:
        virtual void func1()
        {
            cout<<"A::func1()"<<endl;
        }
    };
    
    class B : public A
    {
    public:
        B(){cout<<"B()..."<<endl;}
        ~B(){cout<<"~B()..."<<endl;}
    
    public:
        virtual void func1()
        {
            cout<<"B::func1()"<<endl;
        }
    };
    
    int main()
    {
        A *pb = new B;
        pb->func1();
        delete pb;
    
        system("pause");
        return 0;
    }
    =>A()...
      B()...
      B::func1()
      ~A()...
    注:派生类继承自基类,那么基类就只会存在于派生类中,直到派生类调用析构函数后。
    当上述这种情况,基类的析构函数调用比派生类要早,会造成的一种情况就是类成员不存在了,而类本身却还在,但是类存在的情况下,类成员应该还存在。所以这就矛盾了,应该派生类的析构函数会先被调用,基类的析构函数再被调用。
  • (2)在带有虚函数的基类中定义虚析构函数

    
    #include <iostream>
    
    using namespace std;
    
    class A
    {
    public:
        A(){cout<<"A()..."<<endl;}
        virtual ~A(){cout<<"virtual ~A()..."<<endl;}
    
    public:
        virtual void func1()
        {
            cout<<"A::func1()"<<endl;
        }
    };
    
    class B : public A
    {
    public:
        B(){cout<<"B()..."<<endl;}
        virtual ~B(){cout<<"virtual ~B()..."<<endl;}
    
    public:
        virtual void func1()
        {
            cout<<"B::func1()"<<endl;
        }
    };
    
    int main()
    {
        A *pb = new B;
        pb->func1();
        delete pb;
    
        system("pause");
        return 0;
    }
    =>A()...
      B()...
      B::func1()
      virtual ~B()...
      virtual ~A()...

    注:析构函数的作用并不是删除对象,而是撤销对象占用内存之前完成的一些清理工作。
    (1)抽象类是准备被用做基类的,基类必须要有一个虚析构函数,纯虚函数会产生抽象类,所以在想要成为抽象类的类里声明一个纯虚析构函数。
    (2)定义一个函数为虚函数,不代表该函数未被实现,只是为了来实现多态。
    (3)定义一个函数为纯虚函数,才表示函数未被实现 ,定义它是为了实现一个接口,起一个规范作用。继承抽象类的派生类要实现这个函数。


参考文献:
[1]《C++全方位学习》范磊——第十三章
[2]《C++程序设计教程(第二版)》钱能——第五章、第六章、第七章
[3]《C++ Primer(第5版)》王刚 杨巨峰——第一章、第六章
[4] 百度搜索关键字:C++函数、虚析构函数、纯虚析构函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值