11

To close voters, please help me improve the question so it gets reopened: How can I improve this question so that it gets reopened?

Herb Sutter wrote:

A base class destructor should be either public and virtual, or protected and nonvirtual.

According to that guideline, if you have a class with a public non-virtual destructor, then that class shouldn't be used as a base class. Why not mark it final to enforce that?


But Sutter also wrote the following, implying that final need not be used:

Re "uses of final are rarer" - well, they sort of are. I don’t know of many, and during standardization Bjarne repeatedly asked for examples of problems it solved and patterns where it should be used, and I don’t recall any major ones that stood out.

Another relevant quote, implying that final should be used now that it's available, is from Scott Meyer's Effective C++, item 7:

If you're ever tempted to inherit from a standard container or any other class with a non-virtual destructor, resist the temptation! (Unfortunately, C++ offers no derivation-prevention mechanism akin to Java's final classes or C#'s sealed classes.)

Another data point is that the standard library has no types marked "final", but the reason for that seems to be to avoid breaking code.

There's a similar question here, but not exactly a duplicate as it misses the "protected, nonvirtual" option: Default to making classes either `final` or give them a virtual destructor?

Community
  • 1
  • 1
Jon
  • 5,275
  • 5
  • 39
  • 51
  • You get problems only if you try to delete a derived class object through a pointer to base class. If that doesn't happen in your application - perhaps beacause you don't allocate the objects dynamically - it doesn't matter. – Bo Persson Aug 04 '15 at 13:56

2 Answers2

8

According to that guideline, if you have a class with a public non-virtual destructor, then that class shouldn't be used as a base class. Why not mark it final to enforce that?

Because it's a guideline that fits in certain situations, but not all, so why would you "enforce" it?

It's all very well and good disallowing inheritance where dynamic polymorphism through virtual function calls has not been provisioned, but that's not the only scenario in which we use inheritance.

C++ is multi-paradigm and it doesn't make sense to start enforcing narrow approaches that fit only a subset of use cases. Your suggestion, from what I can tell, essentially boils down to prohibiting people from using inheritance unless they're also going to use dynamic polymorphism.

Lightness Races in Orbit
  • 378,754
  • 76
  • 643
  • 1,055
  • 1
    All the streams have virtual destructors, and the stream buffers have plenty of virtual functions. Not sure that's a great example. – T.C. Aug 04 '15 at 17:54
  • Your last sentence is not entirely accurate because it omits the "protected, nonvirtual destructor" option. – Jon Aug 05 '15 at 01:49
3

I routinely declare classes as final unless they are

  • intended to be used as base classes or
  • POD types.

I think it is a good thing to explicitly design for inheritance (which should be used sparingly after all). And if I didn't bother designing a class as a base class, I document this by declaring it final. If later I find that it would be useful to derive from that class, having to go and remove the final is a good opportunity to also check that the other conditions for making it a viable base class are met.

I usually don't declare POD types as final because I don't see any benefit in doing so and deriving from them is sometimes useful to utilize the empty base optimization.

5gon12eder
  • 24,280
  • 5
  • 45
  • 92
  • Are you describing code for internal use in your organization or personal codebase, or some kind of library you release? If it's the latter case, who's to say others don't find it useful to inherit your class? – einpoklum Aug 04 '15 at 13:45
  • I was mostly talking about code that I have control over. If I were to design a library, I would think twice whether my public types should be derived from. This might lead me to designing a few more of them for inheritance but yes, the remaining types I'd declare as `final`. – 5gon12eder Aug 04 '15 at 13:51
  • 1
    @einpoklum They can and probably should use composition then. – KABoissonneault Aug 04 '15 at 13:52
  • @KABoissonneault that's not always possible, for instance, some `std::tuple` implementations use internal template "leaf" classes which inherit from the `tuple`'s template parameters to benefit from empty base optimization. I suspect using such tuples with a class marked final would cause a compilation error (Edit: unless they avoid inheritance using the `std::is_final` trait, which they should do), but you can't benefit from EBO with composition. – Caninonos Aug 04 '15 at 14:22
  • @Caninonos That's my rational for not declaring POD types `final`. But non-POD types will rarely be empty anyway. – 5gon12eder Aug 04 '15 at 14:25
  • @5gon12eder: Yes, i admit, in that specific case that would be stupid (an empty class can't have any virtual member because of the vtable, not to mention the absence of attributes, and declaring such a class final is... weird). But still, i agree with einpoklum, you shouldn't impose design decisions. – Caninonos Aug 04 '15 at 14:31