例如:
class base
{
public:
base()
{
// allocate memory for basearray
}
virtual ~base()
{
// delete basearray
}
protected:
float* basearray;
};
class derived1 : public base
{
public:
derived1()
{
// allocate memory for derivedarray
}
~derived1()
{
// delete derived array
}
protect:
float* derivedarray;
};
void main()
{
derived1 d;
...
base* pb = &d;
...
// Delete base array?
}
我的基类中有一个虚拟析构函数和一个数组。如果派生类析构函数覆盖基类析构函数,则不会删除基类。什么是一个很好的解决方案?
答案 0 :(得分:9)
在派生类析构函数运行后立即自动调用基类析构函数 。
答案 1 :(得分:2)
当破坏派生对象并且基础的析构函数是虚拟的时,将调用两个析构函数。您可以在此处确认:http://ideone.com/RZamr
顺序将与构造函数的顺序相反,即在构造时,首先调用base
的构造函数,然后调用derived
。首先破坏derived
的析构函数,然后调用base
的析构函数。
答案 2 :(得分:1)
虚拟析构函数的工作方式与其他虚函数的工作方式不同,因为基类的虚析构函数永远不会被覆盖。相反,当子类提供自己的析构函数时,该子类析构函数将触发,然后基类析构函数也会触发。这里使用“虚拟”,这样如果你通过基类指针删除派生类对象,C ++就会知道根据对象的动态类型(子类)而不是指针的静态类型来调用析构函数(超类)。因此,您无需在此处执行任何特殊操作。基类析构函数将照常工作。
希望这有帮助!
答案 3 :(得分:0)
当重写析构函数时,只要将基类析构函数定义为“虚拟”,它仍然会被调用,这就是你所做的。
所以在这个例子中:
class base
{
public:
base()
{
myarray = new float[100];
}
~base()
{
delete[] myarray;
}
private:
float* myarray;
}
class derived : public base
{
public:
derived()
{
}
~derived()
{
}
}
这不会删除'myarray'并且会泄漏内存,因为派生类析构函数隐藏了基类析构函数。但是:
class base
{
public:
base()
{
myarray = new float[100];
}
virtual ~base()
{
delete[] myarray;
}
private:
float* myarray;
}
class derived : public base
{
public:
derived()
{
}
~derived()
{
}
}
这将删除数组。
请记住,构造函数是从基类调用的,因此首先调用基类构造函数,然后调用派生类,而以相反的顺序调用析构函数,因此在之前调用派生类析构函数基类。
答案 4 :(得分:0)
这里没问题。在调用派生类析构函数之后立即调用基类析构函数。
只有一种情况并非如此:对基类的指针调用delete,其中基类析构函数不虚拟。
在所有具有类的本地实例的情况下,在堆栈上创建,并且函数或方法退出,即使由于异常,实例也会被正确销毁。
在类的实例为new
d并且随后通过指向实例化的确切类的指针删除的所有情况下,实例都被正确销毁。
当一个类的实例是new
d但是通过基类指针删除时,只有当基类具有虚拟析构函数(或者声明为virtual
本身或其自身)时,才会正确地破坏该实例自己的基础有一个虚拟的析构函数),实例被正确破坏。