I'm learning C++ and I'm just getting into virtual functions.
From what I've read (in the book and online), virtual functions are functions in the base class that you can override in derived classes.
But earlier in the book, when learning about basic inheritance, I was able to override base functions in derived classes without using virtual
.
So what am I missing here? I know there is more to virtual functions, and it seems to be important so I want to be clear on what it is exactly. I just can't find a straight answer online.
Virtual Functions are used to support Runtime Polymorphism.
That is, virtual keyword tells the compiler not to make the decision (of function binding) at compile time, rather postpone it for runtime".
You can make a function virtual by preceding the keyword
virtual
in its base class declaration. For example,When a Base Class has a virtual member function, any class that inherits from the Base Class can redefine the function with exactly the same prototype i.e. only functionality can be redefined, not the interface of the function.
A Base class pointer can be used to point to Base class object as well as a Derived class object.
You need at least 1 level of inheritance and a downcast to demonstrate it. Here is a very simple example:
Quick Answer:
In Bjarne Stroustrup C++ Programming: Principles and Practice, (14.3):
1.The use of inheritance, run-time polymorphism, and encapsulation is the most common definition of object-oriented programming.
2. You can't code functionality to be any faster or to use less memory using other language features to select among alternatives at run time. Bjarne Stroustrup C++ Programming: Principles and Practice.(14.3.1).
3. Something to tell which function is really invoked when we call the base class containing the virtual function.
Here is a merged version of the C++ code for the first two answers.
Two different results are:
Without #define virtual, it binds at compile time. Animal *ad and func(Animal *) all point to the Animal's says() method.
With #define virtual, it binds at run time. Dog *d, Animal *ad and func(Animal *) point/refer to the Dog's says() method as Dog is their object type. Unless [Dog's says() "woof"] method is not defined, it will be the one searched first in the class tree, i.e. derived classes may override methods of their base classes [Animal's says()].
It is interesting to note that all class attributes (data and methods) in Python are effectively virtual. Since all objects are dynamically created at runtime, there is no type declaration or a need for keyword virtual. Below is Python's version of code:
The output is:
which is identical to C++'s virtual define. Note that d and ad are two different pointer variables referring/pointing to the same Dog instance. The expression (ad is d) returns True and their values are the same <main.Dog object at 0xb79f72cc>.
You need virtual methods for safe downcasting, simplicity and conciseness.
That’s what virtual methods do: they downcast safely, with apparently simple and concise code, avoiding the unsafe manual casts in the more complex and verbose code that you otherwise would have.
Non-virtual method ⇒ static binding
The following code is intentionally “incorrect”. It doesn’t declare the
value
method asvirtual
, and therefore produces an unintended “wrong” result, namely 0:In the line commented as “bad” the
Expression::value
method is called, because the statically known type (the type known at compile time) isExpression
, and thevalue
method is not virtual.Virtual method ⇒ dynamic binding.
Declaring
value
asvirtual
in the statically known typeExpression
ensures that the each call will check what actual type of object this is, and call the relevant implementation ofvalue
for that dynamic type:Here the output is
6.86
as it should be, since the virtual method is called virtually. This is also called dynamic binding of the calls. A little check is performed, finding the actual dynamic type of object, and the relevant method implementation for that dynamic type, is called.The relevant implementation is the one in the most specific (most derived) class.
Note that method implementations in derived classes here are not marked
virtual
, but are instead markedoverride
. They could be markedvirtual
but they’re automatically virtual. Theoverride
keyword ensures that if there is not such a virtual method in some base class, then you’ll get an error (which is desirable).The ugliness of doing this without virtual methods
Without
virtual
one would have to implement some Do It Yourself version of the dynamic binding. It’s this that generally involves unsafe manual downcasting, complexity and verbosity.For the case of a single function, as here, it suffices to store a function pointer in the object and call via that function pointer, but even so it involves some unsafe downcasts, complexity and verbosity, to wit:
One positive way of looking at this is, if you encounter unsafe downcasting, complexity and verbosity as above, then often a virtual method or methods can really help.
If the base class is
Base
, and a derived class isDer
, you can have aBase *p
pointer which actually points to an instance ofDer
. When you callp->foo();
, iffoo
is not virtual, thenBase
's version of it executes, ignoring the fact thatp
actually points to aDer
. If foo is virtual,p->foo()
executes the "leafmost" override offoo
, fully taking into account the actual class of the pointed-to item. So the difference between virtual and non-virtual is actually pretty crucial: the former allow runtime polymorphism, the core concept of OO programming, while the latter don't.