I'm a new to OOP and trying to learn C++ and I came cross polymorphism and using the virtual keyword. I just don't understand why we might need to do that. I've checked this site for similar questions but none of them attempts to answer that why?
-
2I would like to see the list of books you're using to learn C++, because almost every one of those books discusses what purpose `virtual` does, including showing examples of why it is used. – PaulMcKenzie Apr 04 '22 at 13:03
-
I understand the examples and I understand why we need virtual what I don't understand why we need it in the first place. Why not use another derived class to point at the first one why use the base one. – allOverThePlace Apr 04 '22 at 13:07
-
If you forget about polymorphism for a while and imagine a function that can deal with any type of `base` object. Does taking such an object by base class pointer (or reference) make sense? [example](https://godbolt.org/z/4e6MzMWMK) What would the alternative solution look like? – Ted Lyngmo Apr 04 '22 at 13:10
-
you need `virtual` to enable derived classes to override methods. Without `virtual` you cannot override methods – 463035818_is_not_an_ai Apr 04 '22 at 13:12
-
I believe https://stackoverflow.com/questions/2391679/why-do-we-need-virtual-functions-in-c shows by example a use case that would answer the why. – Daniel Apr 04 '22 at 13:19
-
*Why not use another derived class * -- Because the base class implementations using `virtual` doesn't or shouldn't know anything about the derived classes -- all the base class knows about is the base class. So how does the base class "call out" to the derived classes if the base class knows nothing about the derived classes? Enter `virtual`, and `virtual` only works with references and pointers. – PaulMcKenzie Apr 04 '22 at 13:26
-
Google "Dependency Injection" see [Uncle Bob talk](https://youtu.be/QHnLmvDxGTY). – Marek R Apr 04 '22 at 13:54
4 Answers
The main goal is: Separation of concerns.
Let's take an example from my day job. I work on a codebase that does networking. The vast majority of the codebase depends on a class that looks like:
class Transport
{
public:
virtual bool SendMessage(int clientId, string message);
};
Imagine I've got hundred files, and tens of thousand of lines of code, using this class.
Now, my colleague in the low-level team wants to allow our code to use both UDP and TCP for communications. They can simply implement:
class UdpTransport:public Transport
{
public:
bool SendMessage(int clientId, string message) override { /* their code */};
};
class TcpTransport:public Transport
{
public:
bool SendMessage(int clientId, string message) override { /* their code */};
};
This allows me to keep the whole of my code unchanged (using only Transport*
or Transport&
) and not have to worry about what a UdpTransport
or TcpTransport
is. It allows one part of the code to work without knowing what another part of the code is doing.

- 11,063
- 1
- 21
- 42
-
By far this is the best explanation as to why we need it. Understanding the concept based on real use case is always very much helpful. Thank you so much. – allOverThePlace Apr 04 '22 at 13:51
-
In, say, `UdpTransport`, `bool SendMessage(int clientId, string message) override { /* their code */};` :) – Paul Sanders Apr 04 '22 at 16:46
Most introductions of polymorphism start with something like this:
Base* b = new Derived(); // ouch :/
This is very unfortunate in my humble opinion, because it creates the misunderstanding that polymorphism implies manual memory managment via new
. The topics are somewhat related. Though my example of polymorphism would start like this:
#include <iostream>
struct base {
virtual void say_hello() { std::cout << "hello base\n"; }
};
struct derived : base {
void say_hello() override { std::cout << "hello derived\n";}
};
void foo(base& b) {
b.say_hello();
}
int main()
{
base b;
derived d;
foo(b);
foo(d);
}
say_hello
must be declared virtual
to allow derived
to override the method. If say_hello
was not virtual then derived::say_hello
would not override it.
If you remove virtual
and override
above you can see what happens when the method in the derived class does not override the method in the base class. The call b.say_hello()
would then call base::say_hello()
no matter if a base
or derived
is passed to foo
because only for virtual methods the method to be called considers the dynamic type of the object.
What are the use cases for a base class pointer pointing to a derived class object
Same as the reference above. foo(base&)
can take an object of any type that derives from base
and then call its say_hello
method. If this wasnt possible you would have to write a foo(derived)
, foo(derived2)
, foo(derived3)
to call their say_hello
method. In a nutshell, polymorphism means to treat different types the same. foo
does not need to know what the dynamic type of its paramter is. It only needs to know that it inherites from base
.

- 109,796
- 11
- 89
- 185
Many Design Patterns (GOF book) rely on virtual functions. The idea is that you have you work with an object of which you only know it's interface and when you call a function, what is done is based on the object that implements the interface.
One of the design patterns is Command where you have a container in which you can add command implementations and the handler of the container calls the "execute" function without having to worry about what the command actually is. The command implementation contains already the data it needs to run.
A common alternative for virtual functions is a switch case that needs to know all the implementations as an enum so the caller knows what to call exactly or an own implementation of a function-table.
Of course, if you don't see how such thing can improve your program, then it's best not to try and force it in.

- 14,072
- 2
- 31
- 53
Consider the following class architecture and function:
#include <iostream>
#include <string>
class Base
{
public:
std::string hello() const
{
return "Hello Base!";
}
};
class Derived : public Base
{
public:
std::string hello() const
{
return "Hello Derived!";
}
};
void outputHello(const Base& b)
{
std::cout << b.hello() << '\n';
}
We have:
- A base class with a
hello()
method that returns"Hello Base!"
; - A derived class with a
hello()
method that returns"Hello Derived!"
; - A
outputHello(const Base&)
function that takes a reference to aBase
object as its argument and prints out the result of a call to itshello()
method.
Now, what do you think the following program will output?
int main()
{
Base b;
outputHello(b);
Derived d;
// Allowed as a reference/pointer to Base can
// reference/point to a Derived object
outputHello(d);
}
You probably guessed the following if you come from Java or a similar object-oriented language:
Hello Base!
Hello Derived!
But it instead it outputs Hello Base!
twice. Why? It's actually quite simple. When the compiler gets to the outputHello
function body it sees std:cout << b.hello() << '\n'
. It thinks: Well, b
is of type Base
, so I'm gonna issue a call to Base::hello()
. And it does exactly that, regardless of the type of the object we actually pass as argument to outputHello
.
To solve this problem and get the output we expected, we need RTTI (Runtime Type Information), whose name speaks for itself. This is achieved by marking Base::hello()
as virtual:
class Base
{
public:
virtual std::string hello() const
{
return "Hello Base!";
}
};
It is also good practice to mark Derived::hello()
as override
, though it is not necessary — override functions are automatically virtual.
class Derived : public Base
{
public:
std::string hello() const override
{
return "Hello Derived!";
}
};
We then get our expected output.

- 452
- 4
- 14