我对大多数OOP理论都有很好的理解,但最让我困惑的是虚拟析构函数。

我以为析构函数总是被调用,不管是什么,也不管是链中的每个对象。

你打算什么时候让它们虚拟化?为什么?


当前回答

关于virtual的一个基本定义是它确定类的成员函数是否可以在其派生类中被覆盖。

类的D-tor基本上在作用域的末尾被调用,但存在一个问题,例如,当我们在堆(动态分配)上定义一个实例时,我们应该手动删除它。

一旦指令被执行,就会调用基类析构函数,但不会调用派生的析构函数。

一个实际的例子是,在控制场中,你必须操纵效应器和致动器。

在范围结束时,如果没有调用其中一个动力元件(执行器)的析构函数,将产生致命的后果。

#include <iostream>

class Mother{

public:

    Mother(){

          std::cout<<"Mother Ctor"<<std::endl;
    }

    virtual~Mother(){

        std::cout<<"Mother D-tor"<<std::endl;
    }


};

class Child: public Mother{

    public:

    Child(){

        std::cout<<"Child C-tor"<<std::endl;
    }

    ~Child(){

         std::cout<<"Child D-tor"<<std::endl;
    }
};

int main()
{

    Mother *c = new Child();
    delete c;

    return 0;
}

其他回答

在多态基类中声明虚拟的析构函数。这是Scott Meyers的有效C++中的第7项。Meyers接着总结道,如果一个类有任何虚拟函数,那么它应该有一个虚拟析构函数,而不是设计为基类或不是设计为多态使用的类不应该声明虚拟析构器。

任何公开继承的类,无论是否多态,都应该有一个虚拟析构函数。换句话说,如果它可以被基类指针指向,那么它的基类应该有一个虚拟析构函数。

如果是虚拟的,则调用派生类析构函数,然后调用基类析构函数。如果不是虚拟的,则只调用基类析构函数。

虚拟基类析构函数是“最佳实践”——您应该始终使用它们来避免(难以检测)内存泄漏。使用它们,可以确保类的继承链中的所有析构函数都被调用(按正确的顺序)。使用虚拟析构函数从基类继承也会使继承类的析构函数自动虚拟化(因此不必在继承类析构函数声明中重新键入“virtual”)。

简单地说,当您删除指向派生类对象的基类指针时,虚拟析构函数将以正确的顺序析构函数资源。

 #include<iostream>
 using namespace std;
 class B{
    public:
       B(){
          cout<<"B()\n";
       }
       virtual ~B(){ 
          cout<<"~B()\n";
       }
 };
 class D: public B{
    public:
       D(){
          cout<<"D()\n";
       }
       ~D(){
          cout<<"~D()\n";
       }
 };
 int main(){
    B *b = new D();
    delete b;
    return 0;
 }

OUTPUT:
B()
D()
~D()
~B()

==============
If you don't give ~B()  as virtual. then output would be 
B()
D()
~B()
where destruction of ~D() is not done which leads to leak

当您希望不同的析构函数在通过基类指针删除对象时遵循正确的顺序时,析构函数的虚拟关键字是必需的。例如:

Base *myObj = new Derived();
// Some code which is using myObj object
myObj->fun();
//Now delete the object
delete myObj ; 

如果基类析构函数是虚拟的,那么对象将按顺序被析构函数(首先是派生对象,然后是基)。如果基类析构函数不是虚拟的,那么只有基类对象会被删除(因为指针是基类“base*myObj”)。因此派生对象将存在内存泄漏。