C++核心準(zhǔn)則?討論:將基類的析構(gòu)函數(shù)設(shè)為公共和虛擬的,或受保護(hù)的和非虛擬的

Discussion: Make base class destructors public and virtual, or protected and non-virtual
討論:將基類的析構(gòu)函數(shù)設(shè)為公共和虛擬的,或受保護(hù)的和非虛擬的
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.
析構(gòu)函數(shù)應(yīng)該是虛函數(shù)嗎?也就是說,是否應(yīng)該允許通過指向基類的指針進(jìn)行銷毀?如果是,則base的析構(gòu)函數(shù)必須是公共的才能被調(diào)用,否則虛擬調(diào)用它會(huì)導(dǎo)致未定義的行為。否則,應(yīng)該對其進(jìn)行保護(hù),以便只有派生類才能在自己的析構(gòu)函數(shù)中調(diào)用它,這個(gè)析構(gòu)函數(shù)也應(yīng)該是非虛的,因?yàn)樗恍枰摂M地運(yùn)行。
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
基類的常見用法是希望它具有公共派生的類,因此調(diào)用代碼幾乎可以確保使用諸如shared_ptr
class Base {
public:
~Base(); // BAD, not virtual
virtual ~Base(); // GOOD
// ...
};
class Derived : public Base { /* ... */ };
{
unique_ptr pb = make_unique();
// ...
} // ~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:
在極少數(shù)情況下,例如策略類,為方便起見,該類用作基類,而不是多態(tài)行為。建議對那些析構(gòu)函數(shù)進(jìn)行保護(hù)和非虛擬化:
class My_policy {
public:
virtual ~My_policy(); // BAD, public and virtual
protected:
~My_policy(); // GOOD
// ...
};
template
class customizable : Policy { /* ... */ }; // note: private inheritance
Note(注意)
This simple guideline illustrates a subtle issue and reflects modern uses of inheritance and object-oriented design principles.
這個(gè)簡單的指南說明了一個(gè)微妙的問題,并反映了繼承和面向?qū)ο笤O(shè)計(jì)原則的現(xiàn)代用法。
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,調(diào)用代碼可能會(huì)嘗試通過指向Base的指針銷毀派生對象,例如在使用unique_ptr
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:
編寫基類就是定義一個(gè)抽象(請參閱第35到37項(xiàng))。回想一下,對于參與該抽象的每個(gè)成員函數(shù),您需要確定:
Whether it should behave virtually or not.
它是否應(yīng)該表現(xiàn)為虛函數(shù)。
Whether it should be publicly available to all callers using a pointer to?Base?or else be a hidden internal implementation detail.
是否應(yīng)該使用指向Base的指針將其公開給所有調(diào)用者使用,還是作為隱藏的內(nèi)部實(shí)現(xiàn)細(xì)節(jié)。
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項(xiàng)所述,對于普通成員函數(shù),選擇之間是允許以非虛擬方式(通過指向Base的指針)調(diào)用它(但如果它調(diào)用虛擬函數(shù)(例如在NVI或模板方法模式中),則可能具有虛擬行為) ),實(shí)際上還是根本沒有。NVI模式是一種避免公開虛函數(shù)的技術(shù)。
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.
析構(gòu)可以看作只是另一種操作,盡管具有使非虛調(diào)用變得危險(xiǎn)或錯(cuò)誤的特殊語義。因此,對于基類析構(gòu)函數(shù),選擇是根據(jù)是否允許通過指向Base的指針實(shí)際上調(diào)用它?!胺翘摗辈皇且环N選擇。因此,如果可以調(diào)用(即是公共的)基類析構(gòu)函數(shù),則它是虛擬的,否則是非虛擬的。
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模式不能應(yīng)用于析構(gòu)函數(shù),因?yàn)闃?gòu)造函數(shù)和析構(gòu)函數(shù)無法進(jìn)行深度虛擬調(diào)用。(請參閱第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.
推論:編寫基類時(shí),請始終顯式編寫一個(gè)析構(gòu)函數(shù),因?yàn)殡[式生成的是公共的和非虛的。如果默認(rèn)函數(shù)就很好,那么您只需要決定器可見性和虛函數(shù)性,則實(shí)現(xiàn)可以直接使用=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.
某些組件體系結(jié)構(gòu)(例如COM和CORBA)不使用標(biāo)準(zhǔn)的刪除機(jī)制,而是使用不同的協(xié)議來處理對象。遵循特定情況的模式和習(xí)慣用法,并適當(dāng)修改此準(zhǔn)則。
Consider also this rare case:
還要考慮這種罕見的情況:
B?is both a base class and a concrete class that can be instantiated by itself, and so the destructor must be public for?B?objects to be created and destroyed.
B是可以自己實(shí)例化的基類和具體類,因此析構(gòu)函數(shù)必須是公共的,才能創(chuàng)建和銷毀B對象。
Yet?B?also has no virtual functions and is not meant to be used polymorphically, and so although the destructor is public it does not need to be virtual.
但是B也沒有虛函數(shù),并且不打算被多態(tài)使用,因此盡管析構(gòu)函數(shù)是公共的,但它并不需要是虛的。
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.
然后,即使析構(gòu)函數(shù)必須是公共的,也可能會(huì)面臨很大的,不將其虛函數(shù)化的壓力,因?yàn)樽鳛榈谝粋€(gè)虛擬函數(shù),當(dāng)永遠(yuǎn)不需要添加的功能時(shí),它將招致所有運(yùn)行時(shí)類型的開銷。
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.
在這種罕見的情況下,您可以將析構(gòu)函數(shù)設(shè)為公共的和非虛擬的,但要清楚地表明,不允許將衍生出的對象用作B的多態(tài)形式。這正是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.
但是,通常應(yīng)避免使用具體的基類(請參閱第35項(xiàng))。例如,unary_function是typedef的捆綁包,不能獨(dú)立實(shí)例化。給它一個(gè)公開的析構(gòu)函數(shù)確實(shí)沒有任何意義。更好的設(shè)計(jì)是遵循該產(chǎn)品的建議,為其提供受保護(hù)的非虛析構(gòu)函數(shù)。
原文鏈接https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md#discussion-make-base-class-destructors-public-and-virtual-or-protected-and-non-virtual
新書介紹
《實(shí)戰(zhàn)Python設(shè)計(jì)模式》是作者最近出版的新書,拜托多多關(guān)注!

本書利用Python 的標(biāo)準(zhǔn)GUI 工具包tkinter,通過可執(zhí)行的示例對23 個(gè)設(shè)計(jì)模式逐個(gè)進(jìn)行說明。這樣一方面可以使讀者了解真實(shí)的軟件開發(fā)工作中每個(gè)設(shè)計(jì)模式的運(yùn)用場景和想要解決的問題;另一方面通過對這些問題的解決過程進(jìn)行說明,讓讀者明白在編寫代碼時(shí)如何判斷使用設(shè)計(jì)模式的利弊,并合理運(yùn)用設(shè)計(jì)模式。
對設(shè)計(jì)模式感興趣而且希望隨學(xué)隨用的讀者通過本書可以快速跨越從理解到運(yùn)用的門檻;希望學(xué)習(xí)Python GUI 編程的讀者可以將本書中的示例作為設(shè)計(jì)和開發(fā)的參考;使用Python 語言進(jìn)行圖像分析、數(shù)據(jù)處理工作的讀者可以直接以本書中的示例為基礎(chǔ),迅速構(gòu)建自己的系統(tǒng)架構(gòu)。
覺得本文有幫助?請分享給更多人。
關(guān)注微信公眾號(hào)【面向?qū)ο笏伎肌枯p松學(xué)習(xí)每一天!
面向?qū)ο箝_發(fā),面向?qū)ο笏伎迹?/span>
