C++“虚拟函数但没有虚拟析构函数”

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/10024796/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 13:31:11  来源:igfitidea点击:

C++ "Virtual functions but no virtual destructors"

c++

提问by Yukio Fukuzawa

I have a base class Mediaand several derived classes, namely DVD, Book, etc... The base class is written as:

我有一个基类Media和几个派生类,即DVDBook等...的基类写为:

class Media{
    private:
        int id;
        string title;
        int year;
    public:
        Media(){ id = year = 0; title = ""; }
        Media(int _id, string _title, int _year): id(_id), title(_title), year(_year) {}
//      virtual ~Media() = 0;
        void changeID(int newID){ id = newID; }
        virtual void print(ostream &out);
};

The thing is: without the destructor, GCC gives me a bunch of warnings class has virtual functions but non-virtual destructor, but still compiles and my program works fine. Now I want to get rid of those annoying warnings so I satisfy the compiler by adding a virtual destructor, the result is: it doesn't compile, with the error:

问题是:没有析构函数,GCC 给了我一堆警告class has virtual functions but non-virtual destructor,但仍然可以编译并且我的程序运行良好。现在我想摆脱那些烦人的警告,所以我通过添加一个虚拟析构函数来满足编译器,结果是:它不编译,错误:

undefined reference to `Media::~Media()`

Making the destructor pure virtual doesn't solve the problem. So what has gone wrong?

使析构函数纯虚拟并不能解决问题。那么出了什么问题呢?

回答by Luchian Grigore

You need to also define the virtual destructor, not only add it.

您还需要定义虚拟析构函数,而不仅仅是添加它。

//Media.h
class Media{
    //....
    virtual ~Media() = 0;
};

//Media.cpp
#include "Media.h"
//....
Media::~Media() {};

The reason you get the warnings is that all classes that will be derived from should have a virtual or protected (credit @Steve) destructor, otherwise deleting an instance via a pointer to a base class results in undefined behavior.

您收到警告的原因是所有派生自的类都应该有一个虚拟或受保护的(信用@Steve)析构函数,否则通过指向基类的指针删除实例会导致未定义的行为。

Noteyou HAVE TO provide a definition for destructors, even if they are pure virtual.

请注意,您必须为析构函数提供定义,即使它们是纯虚拟的。

回答by Matthieu M.

The thing is: without the destructor, GCC gives me a bunch of warnings "class has virtual functions but non-virtual destructor", but still compiles and my program works fine

问题是:没有析构函数,GCC 给了我一堆警告“类具有虚函数但非虚析构函数”,但仍然可以编译并且我的程序运行良好

This is an annoying warning in Modern C++, but in old object-style C++ it is generally correct.

这是现代 C++ 中令人讨厌的警告,但在旧的对象样式 C++ 中,它通常是正确的。

The problem is about the way your objects are destructed. A simple test:

问题在于您的对象被破坏的方式。一个简单的测试:

#include <iostream>

class Base {};
class Derived: public Base { public: ~Derived() { std::cout << "Aargh\n"; } };

int main() {
  Base* b = new Derived();
  Derived* d = new Derived();

  delete d;
  delete b;
}

This prints:

这打印:

Aargh

Yep, only once.

是的,只有一次。

The problem is that when you call deleteon a variable of type Base*, the Base::~Base()method is called. If it is virtual, then the call is dynamically dispatched to the final method (based on the dynamic type), in this case Derived::~Derived(), but if it is not, then Derived::~Derived()is never called, thus never executed.

问题在于,当您调用deletetype 变量时,会调用Base*Base::~Base()方法。如果是virtual,则调用被动态分派到最终方法(基于动态类型),在这种情况下Derived::~Derived(),但如果不是,则Derived::~Derived()永远不会调用,因此永远不会执行。

Therefore, if you wish to call delete(or use smart pointers which do it for you) on base types, then you need to add virtual ~Base() {}in their class definitions. This is why gcc warns you when you create a polymorphic class without a virtualdestructor.

因此,如果您希望delete在基类型上调用(或使用为您执行此操作的智能指针),那么您需要添加virtual ~Base() {}它们的类定义。这就是为什么当你创建一个没有virtual析构函数的多态类时 gcc 会警告你的原因。



Note: time changed, and since then I implemented -Wdelete-non-virtual-dtorin Clang and it was replicated in gcc as well.

注意:时间变了,从那以后我-Wdelete-non-virtual-dtor在 Clang 中实现,它也在 gcc 中复制。

-Wnon-virtual-dtoris useful for library writers (as it warns on the base class), but may have a higher false positive rate; on the other hand -Wdelete-non-virtual-dtorfires at the call site, and has a much lower false positive rates (which you can generally work around by peppering finalto remove the "polymorphic" property of the class).

-Wnon-virtual-dtor对库编写者很有用(因为它对基类发出警告),但可能有更高的误报率;另一方面-Wdelete-non-virtual-dtor,在调用站点触发,并且误报率要低得多(您通常可以通过final删除类的“多态”属性来解决这个问题)。

回答by Jerry Coffin

What you have commented out is a pure-virtual declaration for a destructor. That means the function must be overridden in a derived class to be able to instantiate an object of that class.

您注释掉的是析构函数的纯虚拟声明。这意味着必须在派生类中重写该函数才能实例化该类的对象。

What you want is just a definition of the destructor as a virtual function:

您想要的只是将析构函数定义为虚函数:

virtual ~Media() {}

回答by lucian.pantelimon

You should implement the virtual destructor, not make it pure virtual.

您应该实现虚拟析构函数,而不是使其成为纯虚拟的。

Look at thissimilar question (identical maybe from the point of view of the virtual destructor error, not the warning) for more info.

查看这个类似的问题(从虚拟析构函数错误的角度来看可能相同,而不是警告)以获取更多信息。

EDIT: more generic solution, in reply to LuchianGrigore's comment (thank you for pointing it out)

编辑:更通用的解决方案,回复 LuchianGrigore 的评论(感谢您指出)

You can also make the destructor pure virtual and implement as it is pointed in the above mentioned question.

您还可以使析构函数纯虚拟并实现上述问题中所指出的。

The use of virtual destructors in you classes should be to prevent instantiation of the base class (i.e. when you have no other pure virtual methods to make the class abstract).

在您的类中使用虚拟析构函数应该是为了防止基类的实例化(即当您没有其他纯虚拟方法来使类抽象时)。

回答by Hiren

Uncomment declaration first and then Try adding following line after class declaration

先取消注释声明,然后尝试在类声明后添加以下行

Media::~Media(){}