使用抽象类时,如何正确删除指针

How to properly delete pointers when using abstract classes

本文关键字:何正确 删除 指针 抽象类      更新时间:2023-10-16

假设我有以下类和对象:

#include <iostream>
class Animal
{
public:
    virtual void makeNoise() = 0;
    void eat()
    {
        std::cout << "Eating..." << "n";
    }
    void sleep()
    {
        std::cout << "Sleeping..." << "n";
    }
};
class Cat: public Animal
{
public:
    void makeNoise()
    {
        std::cout << "Miow..." << "n";
    }
};
class Cow: public Animal
{
public:
    void makeNoise()
    {
        std::cout << "Mooo..." << "n";
    }
};
int main()
{
    Animal *animal;
    Cat *cat = new Cat();
    Cow *cow = new Cow();
    animal = cat;
    animal->eat();
    animal->sleep();
    animal->makeNoise();
    animal = cow;
    animal->eat();
    animal->sleep();
    animal->makeNoise();
    return 0;
}

请注意,动物是抽象类。

如何正确删除指针animalcatcow

当我尝试使用delete animal;时,我会收到以下警告消息:

警告:删除具有抽象类类型的"动物"的对象 非虚拟破坏者将导致不确定的行为。

另一方面,当我尝试使用delete cat;时,我会收到以下消息:

警告:删除具有多态类类型的对象" cat" 非虚拟破坏者可能会导致不确定的行为。

基本的C 规则说,破坏者从派生的类到基类方面的工作方式。当Cat被销毁时,Cat部分首先被销毁,并且Animal部分被破坏。

delete animal;是未定义的行为,因为要正确遵循C 破坏规则,必须在运行时知道,在Animal基本部分之前,应将其派生的类零件销毁。virtual驱动器确实可以做到这一点 - 它启用了一种动态调度机制,以确保破坏按设计工作。

您没有virtual破坏者,因此delete animal只是没有意义。没有办法调用正确的派生级破坏者,只销毁Animal部分也不是有意义的行为。

因此,C 语言对在这种情况下会发生什么没有任何假设。

您的编译器足以警告您。


使用delete cat,情况略有不同。cat指针的静态类型是Cat*,而不是Animal*,因此即使没有任何动态调度机制,也很明显,该机制衍生了级别的驱动器,请先调用。

编译器仍然警告您有关此的信息,但是它以不同的措辞(可能是" vs."会导致")这样做)。我相信原因是Cat本身可能是派生类的基类,因为它已经是具有virtual功能的类层次结构的一部分。

显然不费心执行更完整的代码分析,以发现delete cat确实是无害的。


为了解决此问题,请制作Animal Destructor virtual。当您使用时,用std::unique_ptr替换原始指针。您仍然必须遵循像您这样的类的virtual驱动器规则,但您不再需要执行手册delete

这正是编译器警告您的内容。您需要为每个类定义和实现自己的攻击子,并确保将其定义为virtual的继承。