virtual and override in C++
Tags: cpp, beginners, programming, archaisms
Published: 2022-01-26 15:58:12

Here's an example I wish I'd seen earlier when learning about inheritance in C++.

Let's start with a simple base class.

```cpp
class Base {
public:
	void method() {
		speak("base method\n");
	}
};
```

Here `speak` is just a wrapper around `cout` and `endl`.

```cpp
void speak(const string out) {
	cout << out << endl;
}
```

Let's now inherit from `Base` and re-use the same method name.

```cpp
class Derived : public Base {
public:
	void method() {
		speak("derived method\n");
	}
};
```

So: base classes print "base", derived classes print "derived". However, what happens if we mix types? Concretely, what would the output of the following program be?

```cpp
#include <iostream>
using std::cout;
using std::endl;
using std::string;

// convenience function to print
void speak(const string out) {
	cout << out << endl;
}

class Base {
public:
	void method() {
		speak("base method\n");
	}
};

class Derived : public Base {
public:
	void method() {
		speak("derived method\n");
	}
};


int main() {
	speak("ex1: base class");
	Base base = Base();
	base.method();

	speak("ex2: derived class");
	Derived derived = Derived();
	derived.method();

	speak("ex3: base class ref");
	Base& derived_ref = derived;
	derived_ref.method();

	// Derived& base_ref_error = base;
	// error: non-const lvalue reference to type 'Derived' cannot bind to a 
	// value of unrelated type 'Base'
}
```

Examples 1 and 2 are straightforward. What about example 3? Intuitively, we expect `derived_ref.method()` to print out "derived". It is a reference to a `Derived` object. However, this is the output:

```
ex1: base class
base method

ex2: derived class
derived method

ex3: base class ref
base method
```

Shock! The reason is that, in example 3, `derived_ref` is of type `Base&`. The name is misleading: it's really a `base_ref` :). When it looks for `method` it looks it up in the `Base` class.

When dealing with inheritance this situation is more common than one would like, especially when dealing with abstract classes / interfaces.

As an aside: the last example `Derived& base_ref_error = base;` would not compile if uncommented.

## runtime polymorphism

So, how do we fix example 3 above? The solution is to mark the base class method as `virtual`.

```cpp
#include <iostream>
using std::cout;
using std::endl;
using std::string;

// convenience function to print
void speak(const string out) {
	cout << out << endl;
}

class Base {
public:
	virtual void method() {
		speak("base method\n");
	}
};

class Derived : public Base {
public:
	void method() override {
		speak("derived method\n");
	}
};


int main() {
	speak("ex1: base class");
	Base base = Base();
	base.method();

	speak("ex2: derived class");
	Derived derived = Derived();
	derived.method();

	speak("ex3: base class ref");
	Base& derived_ref = derived;
	derived_ref.method();
}
```

This time the output is:


```
ex1: base class
base method

ex2: derived class
derived method

ex3: base class ref
derived method
```

Great! This makes more sense. The variable `derived_ref` is, after all, built from `derived`, which is of type `Derived`.

Note: the `override` keyword in the `Derived` class is unnecessary. However, it's useful to have it there to help the compiler find bugs.

## abstract classes

A typical scenario where the `virtual` stuff comes up is with abstract classes. Here is an example:

```cpp
class AbstractBase {
public:
	virtual void method() = 0;
	virtual ~AbstractBase() = default;
};
```

We have modified base to have `method` be unimplemented. The `=0` means we _require_ any derived class to implement that method.

We also mark the destructor as `virtual`, as subtle bugs can arise if we don't. See below.

```cpp
#include <iostream>
using std::cout;
using std::endl;
using std::string;

// convenience function to print
void speak(const string out) {
	cout << out << endl;
}

class AbstractBase {
public:
	virtual void method() = 0;
	virtual ~AbstractBase() = default;
};

class Derived : public AbstractBase {
public:
	void method() override {
		speak("derived method\n");
	}
};


int main() {
	// AbstractBase abstractbase = AbstractBase();
	// error: allocating an object of abstract class type 'AbstractBase''Base'

	speak("ex2: derived class");
	Derived derived = Derived();
	derived.method();

	speak("ex3: base class ref");
	AbstractBase& derived_ref = derived;
	derived_ref.method();
}
```

The output is

```
ex2: derived class
derived method

ex3: base class ref
derived method
```

as expected.

As an aside: the first example `AbstractBase abstractbase = AbstractBase();` does not compile, as `AbstractBase` is, indeed, abstract.

## destructors

Let's clarify what happens if we don't have a destructor marked as `virtual`. Here is a first example.

```cpp
#include <iostream>
using std::cout;
using std::endl;
using std::string;

// convenience function to print
void speak(const string out) {
	cout << out << endl;
}

class Base {
public:
	~Base() {
		speak("base destruct");
	}
};

class Derived : public Base {
public:
	~Derived() {
		speak("derived destruct");
	}
};

int main() {
	Derived der; 
}
```

If we run this, the output is

```
derived destruct
base destruct
```

as the destructors for `der` are invoked in order. However, tweaking this slightly, we get some unexpected behavior (I got this example from ["C++ Crash Course" by Josh Lospinoso](https://nostarch.com/cppcrashcourse)).

```cpp
#include <iostream>
using std::cout;
using std::endl;
using std::string;

// convenience function to print
void speak(const string out) {
	cout << out << endl;
}

class Base {
public:
	~Base() {
		speak("base destruct");
	}
};

class Derived : public Base {
public:
	~Derived() {
		speak("derived destruct");
	}
};

int main() {
	Base* x{new Derived()};
	delete x;
}
```

The output is

```
base destruct
```

so `~Derived` is never invoked! This could lead to serious issues. The simple fix is to have the destructor be `virtual`.

```cpp
#include <iostream>
using std::cout;
using std::endl;
using std::string;

// convenience function to print
void speak(const string out) {
	cout << out << endl;
}

class Base {
public:
	virtual ~Base() {
		speak("base destruct");
	}
};

class Derived : public Base {
public:
	~Derived() {
		speak("derived destruct");
	}
};

int main() {
	Base* x{new Derived()};
	delete x;
}
```

so now the output is

```
derived destruct
base destruct
```

as expected.