Modern C++: Safety and Expressiveness with override and final
Tags: cpp, cpp11, tips, tools
Published: 2021-04-14 20:33:32

---
title:Modern C++: Safety and Expressiveness with override and final
published: true
description: 
tags: cpp, cpp11, tips, tools
cover_image: https://www.cppstories.com/2021/images/override-keyword.png
---

While C++11 is with us for a decade now, it's good to go back and recall some of its best features. Today I'd like to consider `override` and `final` keywords which add a crucial safety when you build class hierarchies with lots of virtual member functions.

See how to prevent common bugs, and how to leverage tools to make your code safer.

*Initially published at [CppStories](https://www.cppstories.com/2021/override-final/)*

## An Unexpected Code Path Errors

Can you spot an error in the following code?

There's a base class - `BasePacket` and a single derived class - `NetworkPacket`:

```cpp
class BasePacket {
public:
	virtual ~BasePacket() = default;

	virtual bool Generate() = 0;
	virtual bool Verify(std::string_view ) { return true; }
};

class NetworkPacket : public BasePacket {
public:
	NetworkPacket() = default;

	bool Generate() { return true; }
    
	bool Verify(std::string_view config) const {
		std::cout << "verifying against: " << config;
		return true;
	}

private:
	std::any data_;
};
```

And then we have a simple use case. We'd like to call the `Verify` function using a pointer to the base class:

```cpp
int main() {
	std::unique_ptr<BasePacket> pPacket = std::make_unique<NetworkPacket>();
	pPacket->Verify("test cfg: length: 123: https: false");
}
```

Do you know what's the output here? Give it a try and think a minute.

.

.

.

.

Here's the output:

```

```

Yep, it's an empty line. There's no sensible output as our derived `Verify` function from `NetworkPacket` wasn't called at all!

The reason?

As you can see, we have two different function declaration:

```cpp
bool NetworkPacket::Verify(std::string_view config) const;
```

And

```cpp
virtual bool BasePacket::Verify(std::string_view config);
```

Since they don't match the compiler can call only the base class's function (as we call it through a pointer to the base class). The function from `NetworkPacket` is not available for the overload resolution at this stage.

We can imagine that one developer created the base class, another developer wrote the `NetworkPacket` and wanted to narrow the contract of this particular function and make it `const`.

In our example we have a mismatch on `const`, but it can happen also with parameter types:

```cpp
bool NetworkPacket::Verify(std::string_view config, int arg) const;
// vs
virtual bool BasePacket::Verify(std::string_view config, double arg) const;
```

See the code [@Compiler Explorer](https://godbolt.org/z/onTEEP)

### A Complex Case With `#define`

There's even more fun! See this example:

In one article [@PVS-Studio blog](https://www.viva64.com/en/b/0391/#IDA3BDDAB6E4) there's an interesting case where functions match in 32-bit compilation mode, but when you change to 64-bit, then it fails. Have a look at this synthesised example:

```cpp
//#define WIN64 // uncomment later...

typedef uint32_t DWORD;

#ifdef WIN64
typedef uint64_t DWORD_PTR;
#else
typedef DWORD DWORD_PTR;
#endif

struct Base {
    virtual int execute(DWORD_PTR dwData) { return 1; };
};

struct Derived : public Base {
    int execute(DWORD dwData) { return 2; }; 
};

int run(Base& b) { return b.execute(0); }

int main() {
    Derived d;
    return run(d);
}
```

As you can see above, there's a mismatch in the function declarations. This example is based on a real use case in some WinApi code! The code works nicely in 32 bits when `DWORD` and `DWORD_PTR` matches and both mean `uint32_t`. However, when you define `WIN64` then things came apart and fail.

See the example [@Compiler Explorer](https://godbolt.org/z/TYc4fG). Have a look at the program's output, in one case it's `1`, and in the second case it's `2`.

See more in [Lesson 12. Pattern 4. Virtual functions @PVS-Studio Blog](https://www.viva64.com/en/l/0012/).

### Risks - Sum Up

What do we risk when the virtual functions don't match?

* **Wrong code path might be executed**. This case is particularly scary when you have large hierarchies with complex code; some function may call other base functions, so deducing what's wrong might not be an easy debugging task.
* Hard to read code. Sometimes it's not clear if a function overrides a virtual one from the base class or not. Having a separate keyword makes it visible and explicit.

## The Solution - Apply `override`

Before C++11, it was quite common to have those kinds of errors and misuses. Such bugs were also quite hard to spot early on. Fortunately, following the path of other programming languages like Java or C# Modern C++ gave us a handy keyword `override`.

In C++ we should make a habit of marking every function which overrides with the `override` contextual keyword. Then the compiler knows the expected results and can report an error. In our case when I add `override` to the `NetworkPacket` implementation:

```cpp
bool Verify(std::string_view config) const override {
	std::cout << "verifying against: " << config;
	return true;
}
```

I'll immediately get a compiler error:

```text
 error: 'bool NetworkPacket::Verify(std::string_view) const' marked 'override', but does not override
   21 |  bool Verify(std::string_view config) const override {
      |       ^~~~~~
```

This is much better than getting the wrong path execution after a few days :)

Same happens for our `WIN64` example. When you apply `override` you'll get a nice warning:

```text
error: 'int Derived::execute(DWORD)' marked 'override', but does not override
```

See the improved code [@Compiler Explorer](https://godbolt.org/z/xqcna4).

Additionally, there's also a "reverse" situation:

What if our base class designer forgot to make a function virtual? Then we can expect a similar error.

In both situations, we have to go back and compare the declarations and see what's wrong.

The `override` keyword also reduces the need to write `virtual` in every possible place.

```cpp
struct Base {
    virtual void execute() = 0;
};

struct Derived : public Base {
    virtual void execute() { }; // virtual not needed
};
```

Before C++11, it was common to put `virtual` to mark that this function is overriding, but only the top-most functions in the base class need such a declaration. It's much better to use `override`:

```cpp
struct AnotherDerived : public Base {
    void execute() override { }; // better!
};
```

## Guidelines

Let's also have a look at Core Guidelines: We have a separate topic on `override`:

> C.128: Virtual functions should specify exactly one of `virtual`, `override`, or `final` - [link](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines#c128-virtual-functions-should-specify-exactly-one-of-virtual-override-or-final)

We can read in the guideline with `override` we aim to address the following issues:

* **implicit virtual** - you wanted (or didn't wish to) a function to be virtual, but due to some subtle differences with the declaration it isn't (or is).
* **implicit override** - you wanted (or didn't want) a function to be an override, but it appears to be the opposite way.

We can also have a look at [Google C++ Style Guide](https://google.github.io/styleguide/cppguide.html) where we can find:

> Explicitly annotate overrides of virtual functions or virtual destructors with exactly one of an `override` or (less frequently) `final` specifier. Do not use `virtual` when declaring an override....

## Adding `final`

If you want to block the possibility to override then C++11 also brings another keyword `final`. See the example below:

```cpp
struct Base {
    virtual void doStuff() final;
};

struct Derived : public Base {
    void doStuff(); 
};
```

And Clang reports:

```text
<source>:6:10: error: virtual function 'virtual void Derived::doStuff()' overriding final function
    6 |     void doStuff();
      |          ^~~~~~~
```

See here [@CompilerExplorer](https://godbolt.org/z/EcEEb7)

It's also not a problem to mix `override` with `final` (although it's harder to read and probably uncommon):

```cpp
struct Base {
    virtual void doStuff();
};

struct Derived : public Base {
    void doStuff() override final; 
};

struct ExDerived : public Derived {
    void doStuff() override; 
};
```

This time, we allow to override in one base class, but then we block this possibility later in the hierarchy.

It also appears that the `final` keyword can be used to ensure your functions are properly marked with `override`.

Have a look at this response by [Howard Hinnant](https://stackoverflow.com/users/576911/howard-hinnant):

[c++ - Is there any sense in marking a base class function as both virtual and final? - Stack Overflow](https://stackoverflow.com/questions/16739135/is-there-any-sense-in-marking-a-base-class-function-as-both-virtual-and-final/26514026#26514026)

> I marked the virtual function in the base class with `final`, and the compiler quickly showed me where every single override was declared.  It was then very easy to decorate the overrides how I wanted, and remove the `final` from the virtual in the base class. 

Another interesting use case is with giving the compiler more ways to devirtualise function calls.

See a separate blog post on that in the MSVC Team blog: [The Performance Benefits of Final Classes | C++ Team Blog](https://devblogs.microsoft.com/cppblog/the-performance-benefits-of-final-classes/).

## Tools

After the standardisation of C++11, many useful tools started to appear and catch up with the Standard. One of the best and free tools is `clang-tidy` which offers help with code modernisation.

Usually when you forget to apply `override` the compiler can do nothing about it and won't report any errors.

We can enable `clang-tidy` in Compiler Explorer and if we pass the following command:

```text
--checks='modernize-use-override'
```

We will get the following report:

```text
<source>:19:7: warning: annotate this function with 'override' 
               or (rarely) 'final' [modernize-use-override]
        bool Generate() { return true; }
             ^
            override
<source>:21:7: warning: annotate this function with 'override' 
               or (rarely) 'final' [modernize-use-override]
        bool Verify(std::string_view config) {
             ^
            override
```

Here's the configured Compiler Explorer output: https://godbolt.org/z/jafxTn and the screenshot:

![](../images/clang-tidy-ce.png)

And here's the list of [all checks available in Clang Tidy](https://clang.llvm.org/extra/clang-tidy/checks/list.html). You can experiment and find some other suggestions from the tool. 

If you want to read more you can also have a look at my separate guest post on Clang-Tidy: [A Brief Introduction To Clang-Tidy And Its Role in Visual Assist – Tomato Soup](https://blog.wholetomato.com/2021/01/08/a-brief-introduction-to-clang-tidy-and-its-role-in-visual-assist/).

## Summary

The `override` keyword is very simple to use and makes your code more expressive and more straightforward to read. There's no downside of using it and, as you could see in one example, without it we sometimes risk some unwanted code path to be executed!

For completeness, you can also leverage `final` to have more control over the virtual functions and permissions which classes can or shouldn't override functions.

We also looked at a popular and easy-to-use tool `clang-tidy` that can help us automate the process of modernising code bases.

### Your Turn

* What's your experience with `override`? Do you use it? Is that your habit?
* Have you tried `final`? I'm interested in some good use cases for this feature.

## More from the Author

Bartek is author of two books - ["C++17 In Detail"](https://leanpub.com/cpp17indetail?utm_source=devto&utm_campaign=override) and ["C++ Lambda Story"](https://leanpub.com/cpplambda) - both available @Leanpub - Learn Modern C++ in a practical way.