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

发布于 2024-07-26 09:54:14 字数 223 浏览 8 评论 0原文

可能的重复:
何时使用虚拟析构函数?

C++ 对象的析构函数何时应为虚拟< /代码>?

Possible Duplicate:
When to use virtual destructors?

When should your C++ object's destructor be virtual?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

妖妓 2024-08-02 09:54:14
  1. 你需要虚拟析构函数
    至少一个类方法是
    虚拟的。

这是因为虚方法的原因是要使用多态性。 这意味着您将调用基类指针上的方法,并且您想要最派生的实现 - 这就是多态性的全部要点。

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

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() 时,将调用 ~B() 。

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

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

  1. You need virtual destructor when at
    least one of class methods is
    virtual.

This is because the reason for virtual method is that you want to use polymorphism. Meaning you will call a method on the base class pointer and you want the most derived implementation - this is the whole point of polymorphism.

Now if you did not have virtual destructor and through the pointer to base class you call destructor you end up calling base class destructor. In this case you want polymorphism to work on your destructor as well, e.g. through calling destructor on your base class you want to end up calling destructor of your most derived class not your base class.

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()

having ~A() virtual turns on polymorphism

virtual ~A() {}

So when you now call

delete thing;

~B() will be called.

You would declare virtual destructors when you design class as an interface e.g. you expect it to be extended or implemented. A good practice in that case is to have a interface class (in the sense of Java interfaces) with virtual methods and virtual destructor and then have concrete implementation classes.

You can see that STL classes don't have virtual destructors so they are not supposed to be extended (e.g. std::vector, std::string ...). If you extend std::vector and you call destructor on base class via pointer or reference you will definitely not call your specialized class destructor which may lead to memory leaks.

裸钻 2024-08-02 09:54:14

来自 Stroustrup 的 C++ 风格和技术常见问题解答

那么我什么时候应该声明析构函数
虚拟的? 每当班级有
至少一个虚函数。 拥有
虚函数表明
类旨在充当接口
到派生类,并且当它是时,
派生类的对象可以是
通过指向的指针销毁
基地。

关于当你的析构函数应该是虚拟的时,有很多附加信息C++ 常见问题解答。 (感谢 Stobor)

什么是虚拟会员? 来自 C++ 常见问题解答

[20.1]什么是“虚拟成员函数”?

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

虚函数允许派生
类来替换实现
由基类提供。 这
编译器确保替换是
每当对象出现时总是调用
问题实际上是派生的
类,即使对象被访问
通过基指针而不是
派生指针。 这允许
基类中的算法是
在派生类中替换,即使
用户不知道派生的
类。

派生类可以完全
替换(“覆盖”)基类
成员函数,或派生类
可以部分取代(“增强”)
基类成员函数。 后者
是通过派生来完成的
类成员函数调用基类
类成员函数(如果需要)。

From Stroustrup's C++ Style and Technique FAQ:

So when should I declare a destructor
virtual? Whenever the class has at
least one virtual function. Having
virtual functions indicate that a
class is meant to act as an interface
to derived classes, and when it is, an
object of a derived class may be
destroyed through a pointer to the
base.

Lots of additional info on when your destructor should be virtual on the C++ FAQ. (thanks Stobor)

What is a virtual member? From the C++ FAQ:

[20.1] What is a "virtual member function"?

From an OO perspective, it is the
single most important feature of C++:
[6.9], [6.10].

A virtual function allows derived
classes to replace the implementation
provided by the base class. The
compiler makes sure the replacement is
always called whenever the object in
question is actually of the derived
class, even if the object is accessed
by a base pointer rather than a
derived pointer. This allows
algorithms in the base class to be
replaced in the derived class, even if
users don't know about the derived
class.

The derived class can either fully
replace ("override") the base class
member function, or the derived class
can partially replace ("augment") the
base class member function. The latter
is accomplished by having the derived
class member function call the base
class member function, if desired.

听风吹 2024-08-02 09:54:14

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

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

当然Herb Sutter 给出了理由对他的主张。 请注意,他确实超出了通常的答案“当有人通过基类指针删除派生类对象时”和“如果您的类有任何虚函数,则使您的析构函数成为虚拟的”。

I've recently come to conclude that the fully correct answer is this:

Guideline #4: A base class destructor
should be either public and virtual,
or protected and nonvirtual.

And of course Herb Sutter gives the rationale to his claim. Note that he does go beyond the usual answers "when someone will delete a derived-class object via a base-class pointer" and "make your destructor virtual if your class has any virtual functions".

熊抱啵儿 2024-08-02 09:54:14

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

我采取的方法是,如果我要从一个类派生,那么它应该有一个虚拟析构函数。 在我编写的代码中,实际上没有任何情况表明虚拟析构函数对性能影响很重要,即使现在实际上不需要它,将来当类被修改时也可能需要它。

基本上:将 virtual 放在所有基类析构函数上,除非您有充分的、经过深思熟虑的理由不这样做。

这只是另一条经验法则,但可以防止您以后再犯错误。

If you will (or even might) destroy objects of a derived class through a base class pointer, you need a virtual destructor.

I take the approach that if I'm going to derive from a class AT ALL, then it shall have a virtual destructor. There are effectively no cases in the code I write where the performance implications of a virtual destructor matter, and even if it's not actually needed today, it might end up needing it in the future when the class is modified.

Basically: Put virtual on all base class destructors unless you have a good, well-thought out reason not to.

That's just another rule of thumb, but it's one that keeps you from making later mistakes.

零時差 2024-08-02 09:54:14

总是。

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

Always.

Unless I'm really concerned with the storage and performance overhead of a vtable, I always make it virtual. Unless you have a static analysis tool to verify for you that your destructor is virtual in the right cases, it's not worth making a mistake and failing to make a virtual destructor when it's needed.

樱花坊 2024-08-02 09:54:14

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

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

A base class object should have a virtual destructor, when it is necessary for the base class to do its own cleanup. This is to say, if you have allocated resources in the base class it is necessary for the base class to cleanup, by declaring its destructor virtual you guarantee that this cleanup will be done (assuming you wrote the cleanup correctly).

In general, methods can be defined virtual in a base class, this will allow derived classes to override the virtual methods, implementing their own derived specific implementation. I find this is most clearly demonstrated with a simple example. Say we have a base class 'Shape', now all derived classes may be required to have the ability to draw. The 'Shape' object will not know how to draw classes derived from it, so in the 'Shape' class we define a virtual draw function. ie (virtual void draw();). Now in each base class we can override this function, implementing specific drawing code (ie. a square is drawn differently from a circle).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文