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

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

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

原文地址:https://www.cnblogs.com/xiaobaizzz/p/12334858.html