zoukankan      html  css  js  c++  java
  • 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
      
    • 将基类的虚构函数声明为虚函数后,派生类的析构函数也会自动成为虚函数

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

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

  • 相关阅读:
    如何:为 Silverlight 客户端生成双工服务
    Microsoft Sync Framework 2.1 软件开发包 (SDK)
    Windows 下的安装phpMoAdmin
    asp.net安全检测工具 Padding Oracle 检测
    HTTP Basic Authentication for RESTFul Service
    Windows系统性能分析
    Windows Server AppFabric Management Pack for Operations Manager 2007
    Mongo Database 性能优化
    服务器未能识别 HTTP 标头 SOAPAction 的值
    TCP WAIT状态及其对繁忙的服务器的影响
  • 原文地址:https://www.cnblogs.com/xiaobaizzz/p/12334858.html
Copyright © 2011-2022 走看看