C++ 在析构函数后访问覆盖纯虚函数并设置新值时出现问题

问题描述 投票:0回答:1
#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()错误。

c++ abstract-class destructor pure-virtual
1个回答
0
投票

文档

中所述

析构函数是一个特殊的成员函数,当对象的生命周期结束时调用。

虽然有时可以显式调用它,但这种情况极其罕见且相当复杂。由于调用被破坏对象的方法并调用析构函数两次,您的代码表达了多种未定义行为的情况:

析构函数也可以直接调用,例如摧毁一个物体 使用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(); }
};

然后在派生类中使用相同的函数。

© www.soinside.com 2019 - 2024. All rights reserved.