• C++ 虚析构函数


    • 构造函数不能是虚函数

      • 因为派生类不能继承基类的构造函数,将构造函数声明为虚函数没有意义。
      • 构造函数用于在创建对象时进行初始化工作,在执行构造函数之前对象尚未创建完成,虚函数表尚不存在,也没有指向虚函数表的指针,所以此时无法查询虚函数表,也就不知道要调用哪一个构造函数。
    • 析构函数用于在销毁对象时进行清理工作,可以声明为虚函数,而且有时候必须声明为虚函数。

      #include <iostream>
      using namespace std;
      
      //基类
      class Base{
      public:
          Base();
          ~Base();
      protected:
          char *str;
      };
      //构造函数:分配100个char类型的内存空间
      Base::Base(){
          str = new char[100]; 
          cout<<"Base constructor"<<endl;
      }
      //析构函数:把分配的内存释放掉
      Base::~Base(){
          delete[] str;
          cout<<"Base destructor"<<endl;
      }
      
      //派生类
      class Derived: public Base{
      public:
          Derived();
          ~Derived();
      private:
          char *name;
      };
      Derived::Derived(){
          name = new char[100];
          cout<<"Derived constructor"<<endl;
      }
      Derived::~Derived(){
          delete[] name;
          cout<<"Derived destructor"<<endl;
      }
      
      int main(){
         Base *pb = new Derived(); //基类指针,指向派生类
         delete pb;
      
         cout<<"-------------------"<<endl;
      
         Derived *pd = new Derived(); //派生类指针,指向基类
         delete pd;
      
         return 0;
      }
      
      
      // 指针pd只调用了基类的析构函数,没有调用派生类的析构函数
      Base constructor
      Derived constructor
      Base destructor
      -------------------
      // 指针pd同时调用了基类和派生类的析构函数
      Base constructor
      Derived constructor
      Derived destructor
      Base destructor
      
      
    • 为什么基类指针pb,不会调用派生类的析构函数?

      • 因为这里的析构函数是非虚函数,通过指针访问非虚函数时,编译器会根据指针的类型来确定要调用的函数;
      • 也就是说,指针指向哪个类就调用哪个类的函数;
      • pd是基类指针,所以不管它指向基类的对象还是指向派生类的对象,始终都调用基类的析构函数。
    • 为什么派生类指针pd,会调用派生类和基类的析构函数?

      • 派生类析构函数始终会调用基类的析构函数,并且这个过程是隐式完成的。
      #include <iostream>
      using namespace std;
      
      //基类
      class Base{
      public:
          Base(); //构造函数 
          virtual ~Base(); //析构函数 
      protected:
          char *str;
      };
      Base::Base(){
          str = new char[100];
          cout<<"Base constructor"<<endl;
      }
      Base::~Base(){
          delete[] str;
          cout<<"Base destructor"<<endl;
      }
      
      //派生类
      class Derived: public Base{
      public:
          Derived();
          ~Derived();
      private:
          char *name;
      };
      Derived::Derived(){
          name = new char[100];
          cout<<"Derived constructor"<<endl;
      }
      Derived::~Derived(){
          delete[] name;
          cout<<"Derived destructor"<<endl;
      }
      
      int main(){
         Base *pb = new Derived();
         delete pb;
      
         cout<<"-------------------"<<endl;
      
         Derived *pd = new Derived();
         delete pd;
      
         return 0;
      }
      
      /*运行结果*/
      Base constructor
      Derived constructor
      Derived destructor
      Base destructor
      -------------------
      Base constructor
      Derived constructor
      Derived destructor
      Base destructor
      
    • 将基类的虚构函数声明为虚函数后,派生类的析构函数也会自动成为虚函数

    • 这个时候编译器会忽略指针的类型,而根据指针的指向来选择函数

    • 大部分情况下都应该将基类的析构函数声明为虚函数,否则就有内存泄漏的风险。

  • 相关阅读:
    第六章
    第七章
    第五章
    第四章
    第三章
    第二章
    第一章
    Android深度探索——第十章读书笔记及心得
    Android深度探索——第九章读书笔记及心得
    Android深度探索——第八章读书笔记及心得
  • 原文地址:https://www.cnblogs.com/xiaobaizzz/p/12334858.html
Copyright © 2020-2023  润新知