Virtual, final and override in C++
C++11 added two keywords that allow to better express your intentions with what you want to do with virtual
functions: override
and final
. They allow to express your intentions both to fellow humans reading your code as well as to the compiler.
However, as we will see, the intention of override
is super useful, but the intention of final
… is harder to understand.
Both apply to virtual
functions, which are the member functions of a base class that can be overridden by the classes that derive (inherit) from it.
override
: a useful feature to prevent bugs
override
is a feature to use without moderation! Every time you define a method in the derived class that overrides a virtual
method in the base class, you should tag it override
:
class Base { public: virtual void f() { std::cout << "Base class default behaviour\n"; } }; class Derived : public Base { public: void f() override { std::cout << "Derived class overridden behaviour\n"; } };
This way you show that your intention for the derived class is to override the behaviour of f
in the base class.
Note that in term of execution, the above code is equivalent to this one:
class Derived : public Base { public: void f() { std::cout << "Derived class overridden behaviour\n"; } };
Even without writing override
, f
overrides the behaviour of its counterpart in the base class (as long as the f
of the base class is virtual
and has the same prototype). So override
is really about expressing your intentions.
Expressing your intentions to the compiler
One of the persons (kind of) you can express your intentions to is the compiler. If you tag a member function override
, the compiler will make sure that the member function exists in the base class, and prevent the program from compiling otherwise.
This is particularly useful for const
member functions, because they are error-prone in the context of overriding. For instance, in the above code, if your code in Derived
happens not to modify the object, you could think of tagging the method const
, which is in general a good practice:
class Base { public: virtual void f() { std::cout << "Base class default behaviour\n"; } }; class Derived : public Base { public: void f() const override { std::cout << "Derived class overridden behaviour\n"; } };
But void f()
and void f() const
are two different prototypes, and the derived class no longer overrides the method of the base class. Indeed, the overriding of member functions in C++ is based on prototype (void f()
) and not just on the name of the method (f
).
If you think that a member function overrides another one and in fact it doesn’t, it can lead you into maddening debugging sessions before you understand what is going on.
override
prevents the above code from compiling in the first place.
Note that this is different from using virtual
in the derived class:
class Base { public: virtual void f() { std::cout << "Base class default behaviour\n"; } }; class Derived : public Base { public: virtual void f() const // doesn't check anything! { std::cout << "Derived class overridden behaviour\n"; } };
Adding virtual
here creates a new virtual function that could be overridden in the derived classes of Derived
itself. It doesn’t check that f
in Derived
overrides f
in Base
. The code compiles without a problem and lets the bug slip in.
override
makes the compilation fails when there is a difference in const
like in the above example, and also does it for more visible differences in prototypes, such as adding or removing parameters, or renaming the member function or removing it altogether.
override
makes sure that a base class has an identical prototype in one of its virtual functions.
Maybe you have access to override
without knowing it
override
is a C++11 feature. If you’re stuck with C++98 or C++03, you don’t have access to it in theory.
But if you’re compiling with several compilers, maybe one of them has override
? If it is the case, you could define a macro OVERRIDE
that resolves to override
if you’re compiling with this one, and to an empty string for the other compilers.
You can then define your functions OVERRIDE
, and if they don’t override a virtual function from the base class, this bug will show on the build with the compiler that has override
, and you will be able to fix your code.
override
is such a great help that it’s worth checking if by any chance your compiler(s) implement(s) it.
final
: a useful feature?
final
came along with override
in the C++11 standard. Like override
, you can tag your virtual member function with final
.
class Base { public: virtual void f() { std::cout << "Base class default behaviour\n"; } }; class Derived : public Base { public: void f() final { std::cout << "Derived class overridden behaviour\n"; } };
This prevents any derived class of Derived
to override the member function f
.
So far I have never used final
member functions, and have never seen it used in code.
I guess they can be useful for the implementer of Derived
, to make sure that they know what is actually executed when the member function is called. This can help modify the code of the method later, and have control on how that impacts the program. Indeed, without final
a derived class of Derived
could have overridden the method’s code.
If you use final
member functions, please leave a comment to explain why this is useful.
EDIT: final
can give the compiler an opportunity to improve performance by devirtualization. See this detailed article by Sy Brand for more about this.
final
classes
The final
keyword applies to member function, but unlike override
, it also applies to types:
class X final { // ... };
This prevent the type to be inherited from.
Here again, it is difficult to understand the purpose of such a feature. Andrzej Krzemieński wrote a blog post discussing why we’d make classes final, and the outcome is that there are indeed very few cases where this could be useful, if any. The blog post has an interesting discussion, that also has pretty much the same outcome.
I’m no Java expert, but I gather that the point of final classes in Java is to guarantee that objects of such classes are immutable.
This is pure speculation, but maybe this can apply to C++ too: if a class is final and all of its methods are const, then its interface says that no objects of this class can be modified. Without final, you could have a derived class that adds new member functions that modify the object.
As a result, if you’re passed a reference (or a const reference) to an object of a final class, you have the guarantee that it won’t be modified by someone else, so you can safely use it across threads, reason about it, or whatever benefits of immutable objects.
Check out this post from Andrzej Krzemieński’s blog and its discussion for other suggestions on where final
classes could be useful.
A final
word
In conclusion, override
is super useful to express your intentions in code, and easily prevent some bugs you really don’t want to investigate. You should use it as much as possible.
The purpose of final
is harder to understand. I’ve never used final
on classes or on member functions, nor seen code using it.
Have you used final
in C++, on classes or on methods? How was it useful?
You will also like
Don't want to miss out ? Follow:   Share this post!