#include <iostream>
using namespace std;
class Abstract {
protected:
int* arr;
int size;
public:
Abstract(int s = 10)
{
size = s;
arr = new int[size];
}
virtual ~Abstract()
{
if (arr)
{
delete[] arr;
}
arr = nullptr;
}
virtual void foo() = 0;
void func() { foo(); }
};
class Derived : public Abstract
{
public:
void newArr()
{
Abstract::~Abstract(); // <=> this->~Derived()
arr = new int[size];
}
virtual void foo()override {};
};
int main() {
Derived d;
d.func();//ok
d.newArr();//ok
d.func();//error
return 0;
}
调用抽象类的distractor,并从派生类为arr设置新值后,下一次抽象类使用纯虚函数foo,它不会重定向到派生重写实现,并得到debug abort()错误。
如文档
中所述析构函数是一个特殊的成员函数,当对象的生命周期结束时调用。
虽然有时可以显式调用它,但这种情况极其罕见且相当复杂。由于调用被破坏对象的方法并调用析构函数两次,您的代码表达了多种未定义行为的情况:
析构函数也可以直接调用,例如摧毁一个物体 使用placement-new或通过分配器构建 成员函数,例如 std::allocator::destroy(),用于销毁 通过分配器构造的对象。 请注意,调用 直接对普通对象进行析构,例如局部变量, 当再次调用析构函数时,调用未定义的行为 范围结束。
(重点是我的)
如此简单的解决方案是使用普通方法,在您的情况下可能受到保护,该方法释放数组并从析构函数和您的函数中调用它:
class Abstract {
protected:
int* arr;
int size;
void deallocate()
{
delete[] arr;
arr = nullptr;
}
public:
Abstract(int s = 10)
{
size = s;
arr = new int[size];
}
virtual ~Abstract()
{
deallocate();
}
virtual void foo() = 0;
void func() { foo(); }
};
然后在派生类中使用相同的函数。