In this video, we'll see how we can use base class references and dynamic polymorphism.
In addition to base class pointers,
we can also use base class references and have polymorphic function calls.
This is very useful when we pass objects to functions by reference,
and the functions expect a reference to a base class object.
First, let's see how we can use references directly and achieve dynamic binding of virtual methods.
We'll use the same account class hierarchy that we've used throughout this section.
So let's create an account object a.
And then we'll create a reference ref that's a reference to an account,
that's the base class reference, and we initialize ref to a.
Now if we call the withdraw method using the ref reference,
we're calling the accounts withdraw method, but the binding is dynamic.
Let's see another example with a trust account.
In the second example, we created trust object t.
And then we'll create ref1 as a reference to an account object.
That's the base class reference, and we initialize ref one to t.
Now if we call the withdraw method using the reference ref1,
we call the trust withdraw method.
You can see that this method was bound dynamically.
Let's see a more useful example.
Suppose we have a method called do withdraw,
and it expects a reference to an account object.
Note this is our base class reference.
It also expects a double with the amount to withdraw.
In the function body, we call the withdraw method
of whatever account object was passed in,
and we also use the amount supplied.
So let's call this method with a few objects.
First, we create an account object a.
And we pass a and 1000 to do withdraw.
In the body of the do withdraw function,
we bind the withdraw call to account withdraw dynamically.
Now suppose we create a trust account object named t,
and we pass t and 1000 to do withdraw.
The withdraw method that will be called in the do withdraw method
is the trust withdraw since we're binding it dynamically.
You can see that functions expecting base class references
allow us to think in the general again and not have to worry about details.
So let's head over to the IDE and try some base class references.
So I'm in the IDE. I'm in the section 16 workspace
in the BaseClassReferences project.
And let's go through a couple of simple examples here. First of all,
this is similar to what I did on the slide here.
Let's take a look at these three lines of code right here.
Here we're creating an account object a, and we're using the same account hierarchy
we've been using throughout this section.
So that creates the account object.
And now I've got a ref, that's my variable name.
And it is a reference to an account. That's my base class reference.
And I'm initializing it to a right here.
So when I call ref withdraw,
that's going to bind it dynamically.
And in this case, I happen to be referring to an account.
So it will call account withdraw.
Now in this case here on line 15 through 52, we've got a trust object now,
which is a little bit different.
So ref1, again, is a reference to an account,
that's my base class reference.
And I'm initializing it to t, t is a trust account. So that's perfectly valid.
In this case, when I call ref1's withdraw,
what's going to happen is that method call will be bound dynamically
because it'll realize that ref1
is currently referring to a trust account.
So it'll bind it to trusts withdrawal because they're all virtual methods.
Okay. So that's pretty straightforward I think.
Now let's take a look at this function call. I've got a c++ function up here
on line 40. It's the same one we did on the slides, it's called do withdraw,
and it expects a reference to an account object.
That's my base class reference right there.
It also expects a double, which is going to be passed in.
And then in the body of this function, I'm just calling account and withdraw.
So the idea here is since the withdraw function is a virtual function,
this will be bound dynamically.
And here's an example we're creating four accounts:
a1 a2 a3 and a4, they're all different types.
One's an account, one's a savings account, checking account and trust account,as you can see.
And then I'm calling do withdraw, and I'm passing in a1 a2 a3 and a4.
These methods will be bound dynamically, and we'll see this
behavior, which is exactly what we expect.
Now every compiler vendor is free to implement
dynamic polymorphism using virtual functions however they wish.
But most implementations are pretty similar.
So let's take a look at this. Let's run the debugger.
And I've put in a couple of break points already.
And what's important here is we'll look at all these variables. There's a lot of variables.
We're only interested in a couple.
Now at this point, we have ref and we have ref1,
and all that code already executed but let's take a look at ref.
You can see ref right here,
and you can see that ref is referring to an account, right. That's the whole idea.
Now you also see this bunch of code in here.
You see that vptr, that's your virtual pointer.
So this tells you that there is dynamic polymorphism going on.
But now take a look at ref1. Here's ref1. If we expand ref1,
here you can see that ref1 while it is
a reference to a base class,
it's actually referring to a trust account right now.
And you can see it right there. So you can see the trust account has the account part of it.
And so that's pretty cool. That you can see all that information right in here,
and it really gives you a good idea of what's going on.
Now let's take a look at the do withdraw.
We're right here on line 59. We're about to call do withdraw.
We're about to pass that account a1 in with a 1000.
So I'm going to step through it. And now I'm in do withdraw.
So let's take a look at what account is all about.
In this case, the account that was passed in is a reference to account, right, of course it is.
That's my base class reference. But in this case, when I expand it, you can see
that it's actually referring to an account object since it didn't expand out.
Let's try it one more time, and we'll do it with a2, a2 is a savings account.
So I'll step through that.
And now if we look at account, you can see that account
while it is still a reference to the base class,
it is currently referring to a savings account.
And you can see that the savings account has the account part within it.
So when we execute this and I'll just step through it real quickly, we'll do the last two,
and when we see the output,
and here you can see the output.
So we're doing account withdraw, trusts withdraw, and then we're saying account savings, checking
and trust withdraw, right down here.
So it's exactly like we expect.
So you can see that when you use a base class reference,
you still get the polymorphic behavior, which is pretty cool.
And writing functions like these that expect references to
base class objects is really handy to do,
and it saves you from thinking in detail again.
So I'm thinking here just I want to deposit that amount
to whatever account was passed into me, so I can think very very abstractly.