Stop calling virtual methods in your constructor and destructor!
Tags: cpp
Published: 2022-02-14 09:18:23

---
layout: post
title: Stop calling virtual methods in your constructor and destructor!
published: true
tags: [Cpp]
---

## Why?
* It probably won't do what you want
* It can crash
* Your code may give you a warning or even not compile or link at all and that's how a good compiler should act because you should not do that
* Even if it does what you want, it is error prone because there is a high risk someone else might miss it or won’t understand it

Let's look at this code, what do you think is printed on the console, "Base" or "Derived"?
```C++
#include <iostream>

class Base
{
	public:
		Base()
		{
			speak();
		}

		virtual void speak() const
		{
			std::cout << "Base" << std::endl;
		}
};

class Derived : public Base
{
	public:
		virtual void speak() const override
		{
			std::cout << "Derived" << std::endl;
		}
};

int main()
{
    Derived d;
}
```
It prints "Base" and not "Derived" as you might think. Despite seeming counter intuitive and weird, it is totally normal.

You can see it on compiler explorer [here](https://godbolt.org/z/sTo667jro).

Now let's take this code, what does it do?
```C++
#include <iostream>

class Base
{
	public:
		Base()
		{
			speak();
		}

		virtual void speak() const = 0;
};

class Derived : public Base
{
	public:
		virtual void speak() const override
		{
			std::cout << "Derived" << std::endl;
		}
};

int main()
{
    Derived d;
}
```
[Compiler explorer link](https://godbolt.org/z/j5x1EdG9b).

There is a warning during the compilation looking like this with gcc:
```
	<source>: In constructor 'Base::Base()':
	<source>:7:14: warning: pure virtual 'virtual void Base::speak() const' called from constructor
		7 |         speak();
```
and it does not link!

## Explanations
### How an object of a class using inheritance is constructed and destroyed?
Like an onion, an object has layers. Let’s take the following code as example:
```C++
#include <iostream>

class GrandParent
{
	public:
		GrandParent()
		{
			std::cout << "GrandParent" << std::endl;
		}

		~GrandParent()
		{
			std::cout << "~GrandParent" << std::endl;
		}
};

class Parent : public GrandParent
{
	public:
		Parent()
		{
			std::cout << "Parent" << std::endl;
		}

		~Parent()
		{
			std::cout << "~Parent" << std::endl;
		}
};

class Child : public Parent
{
	public:
		Child()
		{
			std::cout << "Child" << std::endl;
		}

		~Child()
		{
			std::cout << "~Child" << std::endl;
		}
};

int main()
{
    Child onion;
	/* output :
		- GrandParent
		- Parent
		- Child
		- ~Child
		- ~Parent
		- ~GrandParent
	*/
}
```
[Compiler explorer link](https://godbolt.org/z/j88jEhqP8)

The deepest layer corresponds to the class _GrandParent_: it is constructed first and destroyed last.   
The middle layer corresponds to the class _Parent_: it is constructed and destroyed second.  
Lastly, the external layer is corresponding to the class _Child_ and is constructed last and destroyed first.

### A little reminder about how virtual methods works
Each class with at least one virtual method will have a [vtable](https://en.wikipedia.org/wiki/Virtual_method_table), it holds the pointers to all the virtual methods of the class. When an object is created, it will have a pointer to this vtable so it can access when needed. Here's a little example to illustrate the idea:
```C++
#include <iostream>

struct Virtual
{
    virtual void vmethod() {}
};

struct NoVirtual {};

int main()
{
    std::cout << sizeof(Virtual) << std::endl; // 8
    static_assert(sizeof(Virtual) == sizeof(void*)); // Same size as a pointer

    std::cout << sizeof(NoVirtual) << std::endl; // 1, this is the smallest size an object can have and still have a unique address
}
```
[Compiler explorer link](https://godbolt.org/z/dbT4cjcK1)

You can see that the size of an object with a virtual method is a bit bigger, because of the pointer to the vtable.

### The clash
The object has a pointer to the vtable, that’s nice, but this pointer needs to bet set. Remember the metaphor about the onion? Well, the pointer is set during the very beginning of the creation of each layer. You should now grasp the problem: Take for example a class _Base_ inherited by a class _Derived_. If you try calling a virtual method in the constructor of _Base_, when you create an object of type _Derived_, it begins the construction of the “_Base_” layer by setting the pointer to the vtable, then it calls Derived own constructor. In your constructor you have the call to the virtual method, the vtable you have access to right now is the vtable to _Base_ instead of _Derived_.

The same thing happens in opposite order during the destructor call.

Even if it seems counter intuitive, as we have seen, this behavior is logic.

## What if I know what I do?
Even if you think you know what you are doing, don’t do it. It will easily backfire; the code is still confusing. A future maintainer might get confused and make a mistake because even if they have the knowledge about how virtual call works during constructor and destructor, they can miss it as it is hard to spot.


## Sources
- [https://en.wikipedia.org/wiki/Virtual_method_table](https://en.wikipedia.org/wiki/Virtual_method_table)
- [https://en.cppreference.com/w/cpp/language/virtual](https://en.cppreference.com/w/cpp/language/virtual)
- [https://newbedev.com/when-exactly-does-the-virtual-table-pointer-in-c-gets-set-for-an-object](https://newbedev.com/when-exactly-does-the-virtual-table-pointer-in-c-gets-set-for-an-object)