C++ 你的析构函数什么时候应该是虚拟的?

C++ 你的析构函数什么时候应该是虚拟的?,c++,virtual-destructor,C++,Virtual Destructor,可能重复: 何时C++对象的析构函数应该是虚拟< /代码>? 来自: 那么我什么时候应该声明析构函数呢 事实上的只要班上有时间 至少一个虚拟函数。有 虚拟函数表示 类的作用是充当接口 到派生类,如果是,则 派生类的对象可能是 通过指向 基地 很多额外的信息。(谢谢斯托博尔) 什么是虚拟会员?从: [20.1]什么是“虚拟成员功能” 从面向对象的角度来看,它是 C++最重要的一个特性是: [6.9]、[6.10] 虚拟函数允许派生 类来替换实现 由基类提供。这个 编译器确保替换是正确的 始终在对

可能重复:

何时C++对象的析构函数应该是<代码>虚拟< /代码>? 来自:

那么我什么时候应该声明析构函数呢 事实上的只要班上有时间 至少一个虚拟函数。有 虚拟函数表示 类的作用是充当接口 到派生类,如果是,则 派生类的对象可能是 通过指向 基地

很多额外的信息。(谢谢斯托博尔)

什么是虚拟会员?从:

[20.1]什么是“虚拟成员功能”

从面向对象的角度来看,它是 C++最重要的一个特性是: [6.9]、[6.10]

虚拟函数允许派生 类来替换实现 由基类提供。这个 编译器确保替换是正确的 始终在对象处于活动状态时调用 这个问题实际上是一个衍生问题 类,即使对象已被访问 由基指针而不是 派生指针。这允许 要使用的基类中的算法 在派生类中替换,即使 用户不知道派生的 班级

派生类可以完全 替换(“重写”)基类 成员函数或派生类 可以部分替换(“增加”) 基类成员函数。后者 通过使用派生的 类成员函数调用基 类成员函数(如果需要)


当基类需要自己清理时,基类对象应该有一个虚拟析构函数。这就是说,如果您在基类中分配了资源,则基类必须进行清理,通过声明其析构函数virtual,您可以保证将完成此清理(假设您正确编写了清理)

通常,可以在基类中定义虚方法,这将允许派生类重写虚方法,实现它们自己的派生特定实现。我发现用一个简单的例子最清楚地说明了这一点。假设我们有一个基类“Shape”,现在所有派生类可能都需要具有绘制能力。“Shape”对象将不知道如何绘制从它派生的类,因此在“Shape”类中,我们定义了一个虚拟绘制函数。ie(虚拟虚空绘制();)。现在,在每个基类中,我们都可以重写此函数,实现特定的绘图代码(即,正方形的绘图方式与圆形的绘图方式不同)。

始终

除非我真的关心vtable的存储和性能开销,否则我总是将其虚拟化。除非您有一个静态分析工具来验证您的析构函数在正确的情况下是虚拟的,否则在需要虚拟析构函数时犯错误和失败是不值得的

  • 你需要虚拟析构函数在 至少有一个类方法是 虚拟的
  • 这是因为使用虚拟方法的原因是您希望使用多态性。这意味着您将在基类指针上调用一个方法,并且希望得到最派生的实现——这就是多态性的全部要点

    现在,如果您没有虚拟析构函数,并且通过指向基类的指针调用析构函数,那么最终将调用基类析构函数。在这种情况下,您希望多态性也在析构函数上工作,例如,通过对基类调用析构函数,您希望最终调用最派生类的析构函数,而不是基类

    class A
    {
       virtual void f() {}
       ~A() {}
    }
    
    class B : public A
    {
       void f() {}
       ~B() {}
    }
    
    A * thing = new B();
    thing->f(); // calls B's f()
    delete thing; // calls ~A(), not what you wanted, you wanted ~B()
    
    拥有~A()虚拟将启用多态性

    virtual ~A() {}
    
    所以当你现在打电话的时候

    delete thing;
    
    ~B()将被调用

    当您将类设计为接口时,您会声明虚拟析构函数,例如,您希望它被扩展或实现。在这种情况下,一个好的实践是使用虚拟方法和虚拟析构函数创建一个接口类(在Java接口的意义上),然后创建具体的实现类

    您可以看到STL类没有虚拟析构函数,因此它们不应该被扩展(例如std::vector、std::string…)。如果扩展std::vector并通过指针或引用调用基类上的析构函数,则绝对不会调用可能导致内存泄漏的专用类析构函数。

    如果要(甚至可能)通过基类指针销毁派生类的对象,则需要虚拟析构函数

    我采取的方法是,如果我要从一个类派生,那么它应该有一个虚拟析构函数。实际上,在我编写的代码中,虚拟析构函数的性能影响并不重要,即使它在今天实际上并不需要,将来修改类时也可能需要它

    基本上:在所有基类析构函数上都放置虚拟函数,除非您有一个好的、经过深思熟虑的理由不这样做

    这只是另一条经验法则,但它能防止你以后犯错误

    我最近得出结论,完全正确的答案是:

    指南#4:基类析构函数 应该是公开的和虚拟的, 或受保护且非虚拟。


    当然还有他的要求。请注意,他确实超出了通常的回答“当有人将通过基类指针删除派生类对象”和“如果您的类有任何虚拟函数,则将析构函数设置为虚拟的”。

    这不是唯一的情况,但……确切地说,如果没有虚拟函数的父类的子类定义了一个需要清理但不包含在父类中的成员,该怎么办?缺少虚拟析构函数意味着“delete parent”不会调用子类的析构函数……在这种情况下,Stobor,实例化派生类没有什么意义。如果没有动态转换,就无法访问派生类的方法,这意味着需要了解对象类型。这些知识可以用来制作动态电影