讨论:将基类的析构函数设为公共和虚拟的,或受保护的和非虚拟的
Should destruction behave virtually? That is, should destruction through a pointer to a base class be allowed? If yes, then base's destructor must be public in order to be callable, and virtual otherwise calling it results in undefined behavior. Otherwise, it should be protected so that only derived classes can invoke it in their own destructors, and non-virtual since it doesn't need to behave virtually.
析构函数应该是虚函数吗?也就是说,是否应该允许通过指向基类的指针进行销毁?如果是,则base的析构函数必须是公共的才能被调用,否则虚拟调用它会导致未定义的行为。否则,应该对其进行保护,以便只有派生类才能在自己的析构函数中调用它,这个析构函数也应该是非虚的,因为它不需要虚拟地运行。
Example(示例)
The common case for a base class is that it's intended to have publicly derived classes, and so calling code is just about sure to use something like a shared_ptr<base>:
基类的常见用法是希望它具有公共派生的类,因此调用代码几乎可以确保使用诸如shared_ptr <base>之类的东西:
class Base {
public:
~Base(); // BAD, not virtual
virtual ~Base(); // GOOD
// ...
};
class Derived : public Base { /* ... */ };
{
unique_ptr<Base> pb = make_unique<Derived>();
// ...
} // ~pb invokes correct destructor only when ~Base is virtual
In rarer cases, such as policy classes, the class is used as a base class for convenience, not for polymorphic behavior. It is recommended to make those destructors protected and non-virtual:
在极少数情况下,例如策略类,为方便起见,该类用作基类,而不是多态行为。建议对那些析构函数进行保护和非虚拟化:
class My_policy {
public:
virtual ~My_policy(); // BAD, public and virtual
protected:
~My_policy(); // GOOD
// ...
};
template<class Policy>
class customizable : Policy { /* ... */ }; // note: private inheritance
This simple guideline illustrates a subtle issue and reflects modern uses of inheritance and object-oriented design principles.
这个简单的指南说明了一个微妙的问题,并反映了继承和面向对象设计原则的现代用法。
For a base class Base, calling code might try to destroy derived objects through pointers to Base, such as when using a unique_ptr<Base>. If Base's destructor is public and non-virtual (the default), it can be accidentally called on a pointer that actually points to a derived object, in which case the behavior of the attempted deletion is undefined. This state of affairs has led older coding standards to impose a blanket requirement that all base class destructors must be virtual. This is overkill (even if it is the common case); instead, the rule should be to make base class destructors virtual if and only if they are public.
对于基类Base,调用代码可能会尝试通过指向Base的指针销毁派生对象,例如在使用unique_ptr <Base>时。如果Base的析构函数是公共的和非虚拟的(默认值),则可能会意外地在实际上指向派生对象的指针上调用它,在这种情况下,尝试删除的行为是不确定的。这种情况导致较早的编码标准对所有基类析构函数都必须是虚拟的提出了全面的要求。这太过分了(即使是常见情况);相反,规则应该是当且仅当基类析构函数是公共的时,才将它们虚函数化。
To write a base class is to define an abstraction (see Items 35 through 37). Recall that for each member function participating in that abstraction, you need to decide:
编写基类就是定义一个抽象(请参阅第35到37项)。回想一下,对于参与该抽象的每个成员函数,您需要确定:
As described in Item 39, for a normal member function, the choice is between allowing it to be called via a pointer to Base non-virtually (but possibly with virtual behavior if it invokes virtual functions, such as in the NVI or Template Method patterns), virtually, or not at all. The NVI pattern is a technique to avoid public virtual functions.
如第39项所述,对于普通成员函数,选择之间是允许以非虚拟方式(通过指向Base的指针)调用它(但如果它调用虚拟函数(例如在NVI或模板方法模式中),则可能具有虚拟行为) ),实际上还是根本没有。NVI模式是一种避免公开虚函数的技术。
Destruction can be viewed as just another operation, albeit with special semantics that make non-virtual calls dangerous or wrong. For a base class destructor, therefore, the choice is between allowing it to be called via a pointer to Base virtually or not at all; "non-virtually" is not an option. Hence, a base class destructor is virtual if it can be called (i.e., is public), and non-virtual otherwise.
析构可以看作只是另一种操作,尽管具有使非虚调用变得危险或错误的特殊语义。因此,对于基类析构函数,选择是根据是否允许通过指向Base的指针实际上调用它。“非虚”不是一种选择。因此,如果可以调用(即是公共的)基类析构函数,则它是虚拟的,否则是非虚拟的。
Note that the NVI pattern cannot be applied to the destructor because constructors and destructors cannot make deep virtual calls. (See Items 39 and 55.)
注意,NVI模式不能应用于析构函数,因为构造函数和析构函数无法进行深度虚拟调用。(请参阅第39和55条。)
Corollary: When writing a base class, always write a destructor explicitly, because the implicitly generated one is public and non-virtual. You can always=defaultthe implementation if the default body is fine and you're just writing the function to give it the proper visibility and virtuality.
推论:编写基类时,请始终显式编写一个析构函数,因为隐式生成的是公共的和非虚的。如果默认函数就很好,那么您只需要决定器可见性和虚函数性,则实现可以直接使用=default。
Exception(例外)
Some component architectures (e.g., COM and CORBA) don't use a standard deletion mechanism, and foster different protocols for object disposal. Follow the local patterns and idioms, and adapt this guideline as appropriate.
某些组件体系结构(例如COM和CORBA)不使用标准的删除机制,而是使用不同的协议来处理对象。遵循特定情况的模式和习惯用法,并适当修改此准则。
Consider also this rare case:
还要考虑这种罕见的情况:
Then, even though the destructor has to be public, there can be great pressure to not make it virtual because as the first virtual function it would incur all the run-time type overhead when the added functionality should never be needed.
然后,即使析构函数必须是公共的,也可能会面临很大的,不将其虚函数化的压力,因为作为第一个虚拟函数,当永远不需要添加的功能时,它将招致所有运行时类型的开销。
In this rare case, you could make the destructor public and non-virtual but clearly document that further-derived objects must not be used polymorphically as B's. This is what was done with std::unary_function.
在这种罕见的情况下,您可以将析构函数设为公共的和非虚拟的,但要清楚地表明,不允许将衍生出的对象用作B的多态形式。这正是std :: unary_function的功能。
In general, however, avoid concrete base classes (see Item 35). For example, unary_function is a bundle-of-typedefs that was never intended to be instantiated standalone. It really makes no sense to give it a public destructor; a better design would be to follow this Item's advice and give it a protected non-virtual destructor.
但是,通常应避免使用具体的基类(请参阅第35项)。例如,unary_function是typedef的捆绑包,不能独立实例化。给它一个公开的析构函数确实没有任何意义。更好的设计是遵循该产品的建议,为其提供受保护的非虚析构函数。
原文链接https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#discussion-make-base-class-destructors-public-and-virtual-or-protected-and-non-virtual
扫码关注腾讯云开发者
领取腾讯云代金券
Copyright © 2013 - 2025 Tencent Cloud. All Rights Reserved. 腾讯云 版权所有
深圳市腾讯计算机系统有限公司 ICP备案/许可证号:粤B2-20090059 深公网安备号 44030502008569
腾讯云计算(北京)有限责任公司 京ICP证150476号 | 京ICP备11018762号 | 京公网安备号11010802020287
Copyright © 2013 - 2025 Tencent Cloud.
All Rights Reserved. 腾讯云 版权所有