Should I mark my derived class destructors virtual/override? - c++

The C++ core guidelines contain the following advice regarding the virtual, override and final specifiers, specifically relating to derived class destructors:
If a base class destructor is declared virtual, one should avoid declaring derived class destructors virtual or override. Some code base and tools might insist on override for destructors, but that is not the recommendation of these guidelines.
Sure enough, clang-tidy is one of those tools that goes against the recommendation.
If I do not specify either virtual or override, running clang-tidy emits the following warning:
warning: annotate this function with 'override' or (rarely) 'final' [modernize-use-override]
or, if specified just as virtual:
warning: prefer using 'override' or (rarely) 'final' instead of 'virtual' [modernize-use-override]
My question
Given that specifying override, in particular, has the advantage of (at least) ensuing you have correctly specified the base class destructor as virtual, my question boils down to the following specific parts:
What, if any, are the arguments in favour of not specifying virtual or override on derived class destructors?
In your opinion, should I lean more towards the clang-tidy advice, or towards the C++ core guidelines advice?

What, if any, are the arguments in favour of not specifying ... override on derived class destructors?
There are non-conformant compilers that fail to compile when destructor is specified with override: https://msdn.microsoft.com/en-us/library/xfzxhe2a.aspx.
What, if any, are the arguments in favour of not specifying virtual ... on derived class destructors [when it is virtual implicitly]?
Less code is better. You save 7 characters worth by not using redundant virtual.
Counter argument: 7 characters is not much of a saving.
There might be a design decision to make a previously virtual destructor non-virtual for a base class and all of its children. If this guideline (of not specifying redundant virtual) is strictly followed, then only the base needs to be modified. Otherwise each child in the hierarchy must be modified (or at least checked whether they specify virtual separately).
Counter argument: This might be a completely hypothetical situation. Certainly quite rare.
In your opinion, should I lean more towards the clang-tidy advice, or towards the C++ core guidelines advice?
The only argument that has significant weight in my opinion is the non-conformance of old Visual Studio compilers, and thus I would err on the side of not using override on destructors. Otherwise it matters very little and you can follow whichever guideline you prefer, or don't even bother following either - consistency isn't important when the subject at hand makes no difference.

Related

Is it possible to mark a class as non-final/derivable in C++?

I like to use gcc compiler warning -Wsuggest-final-types, which gives valuable information about which classes could be marked as final.
Unfortunately, it also causes this warning for some base classes, which I explicitly created to be derived from (with virtual destructor and some other virtual methods, but no abstract methods). Is there a possibility to mark them in a way that the compiler does not emit this warning/suggestion (and also signal to other developers that they are meant to be derived from)?

Is it a good idea to always mark non-virtual methods with final?

I really don't see a point in overriding non-virtual methods, since it creates a whole range of potential bugs where sometimes original base and sometimes child's method is called.
Following that logic, making a method always come to a simple rule:
Can this method be ever overridden? If Yes - mark it virtual, if no - mark it final.
To me it all sounds well, but I'm wondering if I'm really missing something important and why no one else follows that simple rule?
A program that contains a non-virtual function, and which has every non-virtual function as final and follows the C++ standard, is guaranteed to be completely bug free.
So there is that.
Still: I advise against it.
It also does not exist. The final positional keyword can only be applied to virtual functions. The first paragraph is known as a vacuous satisfaction joke: every example of a non-existing thing has every property, because there are no examples.
Creating a non-overriding virtual final function would be confusing to people reading it. It would prevent a descendent type from declaring a method with identical signature: but it would not prevent a slightly different signature, so it is mostly pointless.
You are absolutely right, each member function that you write must be either explicitly designed to be overridden, or be invariant. However, virtuality is something that you must add at the very top of the hierarchy; you cannot add it in the middle. However, you can "take away" virtuality from this class down by marking a virtual member function final.
Since final can be applied only to virtual member functions, we will not consider non-virtual member functions in the discussion below.
A common practice is to design a class for direct use or for inheritance, but not both, i.e. when you do not instantiate classes in the middle of inheritance hierarchy, and you do not inherit from "leaf" classes of the hierarchy. This practice has been popularized by the More Effective C++ book, item 33. If you follow this practice, you should mark final all virtual functions of leaf classes to let the compiler help you find all violations of the rule.

Is it bad practice to call a virtual function from constructor of a class that is marked final

Normally calling virtual functions from constructors is considered bad practice, because overridden functions in sub-objects will not be called as the objects have not been constructed yet.
But, Consider the following classes:
class base
{
public:
base() {}
~base() {}
private:
virtual void startFSM() = 0;
};
class derived final : public base
, public fsm_action_interface
{
public:
derived() : base{}
, theFSM_{}
{ startFSM(); }
/// FSM interface actions
private:
virtual void startFSM()
{ theFSM_.start(); }
private:
SomeFSMType theFSM_;
}
In this case class derived is marked as final so no o further sub-objects can exist. Ergo the virtual call will resolve correctly (to the most derived type).
Is it still considered bad practice?
This would still be considered bad practice as this sort of this almost always indicates bad design. You'd have to comment the heck out of the code to explain why this works in this one case.
T.C.'s comment above reinforces one of the reasons why this is considered bad practice.
What happens if, a year down the line, you decide that derived
shouldn't be final after all?
That said, in the example above, the pattern will work without issue. This is because the constructor of the most derived type is the one calling the virtual function. This problem manifests itself when a base class's constructor calls a virtual function that resolves to a subtype's implementation. In C++, such a function won't get called, because during base class construction, such calls will never go to a more derived class than that of the currently executing constructor or destructor. In essence, you end up with behavior you didn't expect.
Edit:
All (correct/non-buggy) C++ implementations have to call the version of the function defined at the level of the hierarchy in the current constructor and no further.
The C++ FAQ Lite covers this in section 23.7 in pretty good detail.
Scott Meyers also weighs in on the general issue of calling virtual functions from constructors and destructors in Effective C++ Item 9
Regarding
” Normally calling virtual functions from constructors is considered bad practice, because overridden functions in sub-objects will not be called as the objects have not been constructed yet.
That is not the case. Among competent C++ programmers it’s normally not regarded as bad practice to call virtual functions (except pure virtual ones) from constructors, because C++ is designed to handle that well. In contrast to languages like Java and C#, where it might result in a call to a method on an as yet uninitialized derived class sub-object.
Note that the dynamic adjustment of dynamic type has a runtime cost.
In a language oriented towards ultimate efficiency, with "you don't pay for what you don't use" as a main guiding principle, that means that it's an important and very much intentional feature, not an arbitrary choice. It's there for one purpose only. Namely to support those calls.
Regarding
” In this case class derived is marked as final so no o further sub-objects can exist. Ergo the virtual call will resolve correctly (to the most derived type).
The C++ standard guarantees that at the time of construction execution for a class T, the dynamic type is T.
Thus there was no problem about resolving to incorrect type, in the first place.
Regarding
” Is it still considered bad practice?
It is indeed bad practice to declare a member function virtual in a final class, because that’s meaningless. The “still” is not very meaningful either.
Sorry, I didn't see that the virtual member function was inherited as such.
Best practice for marking a member function as an override or implementation of pure virtual, is to use the keyword override, not to mark it as virtual.
Thus:
void startFSM() override
{ theFSM_.start(); }
This ensures a compilation error if it is not an override/implementation.
It can work, but why does startFSM() need to be virtual? In no case do you actually want to actually call anything but derived::startFSM(), so why have any dynamic binding at all? If you want to have it call the same thing as a dynamically binded method, make another non-virtual function called startFSM_impl() and have both the constructor and startFSM() call it instead.
Always prefer non-virtual to virtual if you can help it.

C++ vtable resolving with virtual inheritance

I was curious about C++ and virtual inheritance - in particular, the way that vtable conflicts are resolved between bass and child classes. I won't pretend to understand the specifics on how they work, but what I've gleamed so far is that their is a small delay caused by using virtual functions due to that resolution. My question then is if the base class is blank - ie, its virtual functions are defined as:
virtual void doStuff() = 0;
Does this mean that the resolution is not necessary, because there's only one set of functions to pick from?
Forgive me if this is an stupid question - as I said, I don't understand how vtables work so I don't really know any better.
EDIT
So if I have an abstract class with two seperate child classes:
A
/ \
/ \
B C
There is no performance hit when calling functions from the child classes compared to say, just a single inheritance free class?
There is no hit for calling nonvirtual functions in the child class. If you're calling an overridden version of your pure virtual function as in your example, then the virtual penalty may still exist. In general it's difficult for compilers to optimize away the use of the virtual table except under very specific circumstances, where it knows the exact by-value type of the object in question (from context).
But seriously don't worry about the overhead. It's going to be so little that in practice you will almost certainly never encounter a situation where it's the part of code causing performance bottlenecks. Use virtual functions where they make sense for your design and don't worry about the (tiny) performance penalty.
I don't know what "one set of functions" you are talking about. You have two derived classes - B and C - with each having its own set of virtual functions. So, you have at least two sets, even if all functions in A are pure.
The virtual dispatch occurs when the compiler does not know the dynamic type of the object it is working with. For example, if your have a pointer A *p, it can point to an object of type B or type C. If the compiler does not know what is the actual type of the object p is pointing to, it will have to use virtual dispatch in order to call virtual functions through p.
P.S. There's no "virtual inheritance" in your example. The term virtual inheritance in C++ has its own meaning. And you are not talking about virtual inheritance here.
The 'double dispatch' hit only occurs when the method is virtual. If the derived method is not virtual, there is no performance hit.

C++ Style: Prefixing virtual keyword to overridden methods

I've been having a discussion with my coworkers as to whether to prefix overridden methods with the virtual keyword, or only at the originating base class.
I tend to prefix all virtual methods (that is, methods involving a vtable lookup) with the virtual keyword. My rationale is threefold:
Given that C++ lacks an override
keyword, the presence of the virtual
keyword at least notifies you that
the method involves a lookup and
could theoretically be overridden by
further specializations, or could be
called through a pointer to a higher
base class.
Consistently using this style
means that, when you see a method
(at least within our code) without
the virtual keyword, you can
initially assume that it is neither
derived from a base nor specialized
in subclass.
If, through some error, the
virtual were removed from IFoo, all
children will still function
(CFooSpecialization::DoBar would
still override CFooBase::DoBar,
rather than simply hiding it).
The argument against the practice, as I understood it, was, "But that method isn't virtual" (which I believe is invalid, and borne from a misunderstanding of virtuality), and "When I see the virtual keyword, I expect that means someone is deriving from it, and go searching for them."
The hypothetical classes may be spread across several files, and there are several specializations.
class IFoo {
public:
virtual void DoBar() = 0;
void DoBaz();
};
class CFooBase : public IFoo {
public:
virtual void DoBar(); // Default implementation
void DoZap();
};
class CFooSpecialization : public CFooBase {
public:
virtual void DoBar(); // Specialized implementation
};
Stylistically, would you remove the virtual keyword from the two derived classes? If so, why? What are Stack Overflow's thoughts here?
I completely agree with your rationale. It's a good reminder that the method will have dynamic dispatch semantics when called. The "that method isn't virtual" argument that you co-worker is using is completely bogus. He's mixed up the concepts of virtual and pure-virtual.
A function once a virtual always a virtual.
So in any event if the virtual keyword is not used in the subsequent classes, it does not prevent the function/method from being 'virtual' i.e. be overridden. So one of the projects that I worked-in, had the following guideline which I somewhat liked :
If the function/method is supposed to
be overridden always use the
'virtual' keyword. This is especially
true when used in interface / base
classes.
If the derived class is supposed to
be sub-classed further explicity
state the 'virtual' keyword for every
function/method that can be
overridden. C++11 use the 'override' keyword
If the function/method in the derived
class is not supposed to be
sub-classed again, then the keyword
'virtual' is to be commented
indicating that the function/method
was overridden but there are no
further classes that override it
again. This ofcourse does not prevent
someone from overriding in the
derived class unless the class
is made final (non-derivable), but it
indicates that the method is not supposed to be
overridden.
Ex: /*virtual*/ void guiFocusEvent();
C++11, use the 'final' keyword along with the 'override'
Ex: void guiFocusEvent() override final;
Adding virtual does not have a significant impact either way. I tend to prefer it but it's really a subjective issue. However, if you make sure to use the override and sealed keywords in Visual C++, you'll gain a significant improvement in ability to catch errors at compile time.
I include the following lines in my PCH:
#if _MSC_VER >= 1400
#define OVERRIDE override
#define SEALED sealed
#else
#define OVERRIDE
#define SEALED
#endif
I would tend not to use any syntax that the compiler will allow me to omit. Having said that, part of the design of C# (in an attempt to improve over C++) was to require overrides of virtual methods to be labeled as "override", and that seems to be a reasonable idea. My concern is that, since it's completely optional, it's only a matter of time before someone omits it, and by then you'll have gotten into the habit of expecting overrides to be have "virtual" specified. Maybe it's best to just live within the limitations of the language, then.
I can think of one disadvantage:
When a class member function is not overridden and you declare it virtual, you add an uneccessary entry in the virtual table for that class definition.
Note: My answer regards C++03 which some of us are still stuck with. C++11 has the override and final keywords as #JustinTime suggests in the comments which should probably be used instead of the following suggestion.
There are plenty of answers already and two contrary opinions that stand out the most. I want to combine what #280Z28 mentioned in his answer with #StevenSudit's opinion and #Abhay's style guidelines.
I disagree with #280Z28 and wouldn't use Microsoft's language extensions unless you are certain that you will only ever use that code on Windows.
But I do like the keywords. So why not just use a #define-d keyword addition for clarity?
#define OVERRIDE
#define SEALED
or
#define OVERRIDE virtual
#define SEALED virtual
The difference being your decision on what you want to happen in the case you outline in your 3rd point.
3 - If, through some error, the virtual were removed from IFoo, all children will still function (CFooSpecialization::DoBar would still override CFooBase::DoBar, rather than simply hiding it).
Though I would argue that it is a programming error so there is no "fix" and you probably shouldn't even bother mitigating it but should ensure it crashes or notifies the programmer in some other way (though I can't think of one right now).
Should you chose the first option and don't like adding #define's then you can just use comments like:
/* override */
/* sealed */
And that should do the job for all cases where you want clarity, because I don't consider the word virtual to be clear enough for what you want it to do.