C++:错误的析构函数被调用

3

ProjectileNode 的子类。 我想要调用 Projectile 析构函数。

注意:在实际情况中,我有一个指向ProjectilePlayerEnemyNode*列表,每个都有自己的析构函数。

Node.h 文件 中没有指定析构函数(我假设它使用默认的析构函数)。

    Node* p = new Projectile();
    delete(p); //Projectile destructor is never called

1
可能是重复的问题:何时使用虚析构函数? - LogicStuff
你的意思是 Projectile 继承自 Node 吗?如果是这样的话,“超类”这个术语用于将 ProjectileNode 相关联是不正确的。 - crashmstr
默认析构函数不是虚拟的。如果还没有这样做,请提高编译器警告级别(在g++中,-Wall应该足够),你会看到编译器告诉你你所写的代码将无法工作。 - user4581301
4个回答

4
首先,从您的问题中可以明显看出ProjectileNode的一个子类(参见维基百科条目)。如果您有一个像Node这样用于派生的类,则应确保其析构函数是虚拟的:
class Node
{
...
    virtual ~Node();
};

当你删除一个指向超类的指针时,这将导致编译器调用适当的类析构函数

(另一个问题是它是否应该是纯虚函数。)


你知道吗,我从来没有尝试过纯虚析构函数。这个明天就加入实验队列了。 - user4581301
为什么不是所有的函数都是虚函数?它们不是虚函数有什么优势吗? - RainingChain
有几个原因。其中之一是使用它们会带来运行时开销,而C++的哲学是“只为你使用的功能付费”。Bjarne Stroustrup写了一本关于这些问题的书,类似于“C++语言的设计与演化”。 - Ami Tavory

2

你需要将Node的析构函数设置为virtual,默认的(非虚拟)析构函数在这里无法满足需求,即动态多态性将无法发挥作用。

class Node {
public:
    virtual ~Node() {}
}

2

C++ 是一种静态类型语言,所以从这个语句 Node* p = new Projectile(); 开始编译器会将 p 视为 Node 对象。在销毁 p 时,只会调用 Node 类的析构函数。

要解决这种情况,需要使用 virtual

代码:

class Node {
  public:
    virtual ~Node() {
      //delete resources allocated in Node class
    }
};

class Projectile : public Node {
  public:
    ~Projectile() {
       //delete resources allocated in Projectile class
     }
};

0

简短回答:

将你在Node中的析构函数声明为虚函数。

class Node {
  // Stuff...
  virtual ~Node();
};

不那么简短的答案:

Projectile和类似的类继承自Node时,数据成员和函数会从Node中继承。派生类可以覆盖或替换父类中实际的函数定义。这种覆盖可以在编译时或运行时发生,取决于基类中的函数是否声明为“虚拟的”。

对于非虚拟析构函数,要调用的析构函数由指针的类型确定。因此,即使指针变量p指向一个Projectile的实例,delete(p)也会调用在Node中定义的析构函数。

对于虚拟析构函数,要调用的析构函数是在运行时确定的。因此,无论指针的类型如何,被调用的析构函数将是由p所指对象中定义的那个。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接