In this video, we'll learn about the virtual keyword,
virtual functions and how to declare them in your own class hierarchies.
When we derive a class from a base class,
we can redefine the base classes functions behaviors in the derived class.
This creates a specialized version of the function specific to the derived class.
If we don't use the virtual keyword with these functions,
then they're statically bound at compile time as we've already seen.
Overridden functions are bound dynamically.
We do this by declaring the function to be virtual.
So virtual functions are overridden functions,
and they allow us to think abstractly by treating all objects in the hierarchy
as objects of the base class.
Let's see the syntax for declaring a function as virtual.
First, we declare the function we want to override in our derived classes
as virtual in the base class.
You can see in the code snippet that we're in the account base class,
and we declare the withdraw method as virtual
by preceding the functions prototype with the virtual keyword.
This makes withdraw a virtual function,
which means it can be overridden in derived classes
and it will be bound dynamically at runtime when we use a base class pointer
or reference.
Once we declare a function as virtual,
then that function is virtual all the way down the class hierarchy from this point forward.
Here we can see an example of overriding the withdraw function and the derived class checking.
The derived withdraw function will be implicitly virtual,
so we don't have to use the virtual keyword again,
but it's best practice to do so.
It's important to understand that in order to override a base classes function,
the function's signature and return type must match exactly.
If you don't match it exactly, the compiler will treat it as a redefinition
and statically bind it.
That's it. It's pretty simple and provides so much power.
Remember, virtual functions are dynamically bound
only when we call them via a base class pointer or reference.
Otherwise, they're statically bound.
So let's head over to the IDE and make that simple account
class hierarchy dynamically polymorphic with virtual functions.
It's so easy to do.
Okay. So I'm in the IDE. I'm in section 16 workspace,
and I'm in the VirtualFunctions project.
All right. So here we've got the simple account hierarchy. You can see we've got an account class,
a checking account, a savings account and a trust account, and they're all accounts.
And right now we've all -- we've only got the withdraw method,
and it's been redefined in every single class.
And all we're doing is just displaying in account withdraw, in checking withdraw.
You've seen this one before. This just tells you which one is being called
so that we can better follow it.
So there are my four classes.
And right now, it's -- you can see there's no virtual keywords in here at all.
So this is not going to use dynamic binding.
Here are pointers. Again, p1 p2 p3 p4,
each one pointing to a different type of a account,
and we're just simply calling the withdraw method for each one,
and then we're cleaning up our pointers.
Now, since we don't have dynamic polymorphism when we run this,
we expect all four of these
methods to be bound to the account classes withdraw.
So let's run that and be sure that that's our starting point.
And that's exactly what we see here.
Those are the withdraw methods executing right here. We're executing account withdraw
for all four of them because we're using static binding.
All right. So now let's make this polymorphic.
What do we do?
So we go to our base class, and we look at the functions that we want
our derived classes to be able to override.
And those are the ones that we want to make virtual.
There's only one example here, but typically you would have several in a base class.
In this case, this is the one, withdraw. So all you need to do is put virtual in front.
That's it. That's a virtual function now.
Whenever I come at any derived object via a base class pointer
or a base class reference, it'll be dynamically bound.
That's as simple as that. It's pretty powerful.
Now I don't have to put the virtual keyword down here,
but it's best practice to do so because many times
users will be looking at this class here
and it's nice for them to see that it is indeed virtual.
So let's do this, virtual here. I'll just copy that.
We'll do it here.
And we'll do it one more time right here.
So now every one of these classes has overridden
the withdraw method.
All right. That's it. That's all we really have to do. If we run this now,
we'll get our polymorphic behavior, which is exactly what we want. You see that
in account withdraw and savings withdraw and checking withdraw and trust withdraw.
This is awesome.
I mean one simple keyword, you get a lot of bang for your buck here.
There's a lot going on. Now you'll notice a few things.
We're getting some warnings here,
and we're getting four warnings, and they're all about destructors.
Whenever you have a virtual function,
you need to have virtual destructors.
And that's what we're going to talk about in the next video.
So you can see how simple this was to do and the power that it gives you.
In the next video, we'll address these warnings,
and we'll talk about virtual destructors.