Okay. So welcome back. This is part 2 of the solution to the section
16 challenge on polymorphism.
If you recall in the last part, what we did was we took the account class,
and we made it an abstract base class by adding
those two pure virtual functions for deposit and withdraw.
Then we went through all the classes, gave them all virtual destructors,
made sure our deposits and our withdrawal methods were running correctly and so forth.
So everything was working great.
And right now, the source code that you see in challenge solution-part2 project,
which is the active project right now is exactly where we left off in part 1.
And this is the only test case I'm really interested in right now.
I've got a base class pointer. I'm creating a new trust account,
and I'm displaying that object
on an output stream. And when I run this,
I don't really get what i want.
I get the account part of the object. You remember, what we talked about last time.
So what that means is that this is being statically bound, not dynamically bound,
and the object is being sliced so the trust account part of it is being discarded.
And we're displaying account instead of trust account.
The account name Leo and the account name balance, which is part of that account part of me,
but the interest rate is not displaying.
And the same will be true for savings and checking accounts.
So what's the fix? Well, there s a lot of ways to fix this.
But the way we're going to fix it is we're going to create
an interface class called I printable.
And we're going to let account be derived from I printable.
And then all of the concrete classes will implement
how they want to be displayed.
Okay. So let's get started with that.
So the first thing we want to do is we want to create the I printable class.
So you can right click here on source
and select new class and give it the name I printable and you could just call it printable if you like.
I'll name it I printable,
and the block guard I'll use is just I_printable
_h underscore just like we've done before.
You can choose to leave this blank, and CodeLite will generate one for you.
That's it. I'll select okay. So there's my I printable class.
You can see right now it's a real simple class.
And what we want to do is implement this.
So let's look at the header file first.
We need to include iostream since we're going to use an ostream.
So we'll do that right away, and there's my class i printable.
We don't need a constructor.
And we want our
de-structure to be virtual because we're going to have a pure virtual function in here.
So we want this to be virtual, and we want the compiler to just generate one for us.
We don't need anything special. We don't have raw pointers.
We're not -- we don't have any resources that we have to clean up.
Okay. So there's my virtual destructor.
Now I want to have another function. This is going to be a pure virtual function.
And it's going to be called print. We can call this anything you like,
and it expects a std ostream.
And it's going to be by reference, and I'll call it OS.
It's a const virtual function. We don't want it to modify anything,
and it's pure. So I'm going to add the equal 0 at the end.
Okay. So now we also need to create a friend function here.
And the reason we're creating the friend function is for the syntax, right.
Remember, when we're using the insertion operator, we want to stream on the left side
and the object that we want to display on the right side.
I can't do that with amember function, so I'm going to use a friend function.
So we will say friend
and it's going to return a std ostream by reference.
What are we overloading, we're overloading the insertion operator.
And what are the parameters. Well, the first one is std ostream
by reference. Again, I'll call that OS.
And the second parameter is a const I printable.
It's really important that this is an I printable, not an account, not anything else.
Since an account will be derived from an I printable,
everything in that hierarchy will also be an eye principle and conform to this interface,
and we can call this object or right-hand side or whatever you like.
I'll just call it object. That's it. That's our class.
Now what we need to do is we need to implement this function right here.
And we'll do that in the I printable implementation file right here. We'll get rid of all of this.
And I'll include iostream up here.
Perfect. So let's implement this function right here.
So what is this function all about. This is the function that really runs everything.
We're going to get an I printable object here by reference.
So we know that, that object has already overridden print.
It must have right, otherwise it wouldn't have compiled.
So what we can do here is we can simply call obj.print.
And that reference to the output stream.
That's pretty cool. And you notice that, that matches this guy right here, right.
right. There's print, and there's the ostream.
Now remember all the classes in our account class hierarchy
are going to override this virtual function.
So they'll be printable. It's really as simple as that.
So that's it. We're going to put that --
we're going to call the objects print, and then we're just going to return OS,
and we are done. It's a real, real simple interface.
Perfect.
Now let's go to our account.
And what are we going to do here.
Well, you know what we're going to leave taking this guy out for last because
we really do need to take him out. But for now, let's just leave him in.
But what we need to do first is we need to be printable,
right. So let's come over here and we will include
I printable.
So now we've got the header file, and we want our accounts to be
derived publicly from I printable.
So what does that tell you now, an account is an I printable,
right, and I printable has this pure virtual function.
So that account needs to override that function, and then it becomes printable.
All right. So let's come over here, and what's the function.
The function is virtual,
void print. It expects a std ostream ref,
it's const, and I'm overriding it.
So you're telling the compiler exactly what's going on here.
This guy is a pure virtual function in the I printable interface class.
You're telling the compiler that you plan to override it.
Please check this signature, make sure I get it right.
So I'm going to copy this because we need to do that in all our classes
in the class hierarchy.
So this is account.h.
I'm going to go to checkingaccount.h, and I'm going to put it right in here.
I'm going to go to savingsaccount.h, put it right in here.
And finally, I'm going to go to trustaccount.h and put it right in there.
Perfect.
So now what do we need to do, we actually need to
override that function. Do what we say we were going to do.
So where do we do that. Well, we do that in the cpp file.
So here's my account header file.
This is the function that we want to override.
And what we want to do is we want to say okay if I'm an account,
this is how I'm going to print myself. If I'm a checking account, this is how i want to print myself.
So it's very similar to what we did earlier with those friend -- with this friend function right here.
And we can -- just about to get rid of that. We can actually get rid of it now
but I like getting rid of it at the very end, so we'll do that.
So here's my account cpp.
And let me copy this since that's the one that we need to override in here.
So I'm going to come right over here.
And you notice this line right here,
we're going to reuse that line because that's how we want to print an account.
Let's override this function.
This is the print function for the account class.
And we can get rid of the override. We don't need that here.
So what do we do here. Well, let's just set the precision for the output stream. Since we're printing numbers,
we'll just print them to two decimal places.
And what we'll do is we'll also display fixed point
that way it looks nicer as well.
Okay. Now what do we want to do here. Well,
we want to do what we said we were going to do, right
We want to display the account information. This is how we do it.
So we just need to copy that right in here.
Now there's only one little thing, this is now a member, right.
So we don't need to do account dot. We could just get rid of all that
we did that we had to do that before because it was a friend.
But now we can just access those members directly since we're members.
And now we can get rid of this guy, don't need him anymore.
We can go back to our header file and get rid of the friend.
That's it. So now this account class
is using that overridden functionality to print itself.
So let's do that for the other one. So we'll go to checking account.
There it is. So it's good to go here. We'll go to the implementation.
And what we'll do is we'll implement this function again.
Again, we don't have to say virtual here.
We can simply say this is the checking account
print method.
We can get rid of the override,
and then we can write the same code that we wrote before.
And finally, we just display how we want to display it.
Okay. Pretty easy.
And now we can get rid of this guy,
and we come to the header file and get rid of our friend.
Okay. So you can see the steps involved. I'll go ahead and do the last two.
Okay. So I've gone ahead and implemented that print function
in all of these classes.So here's the print for account,
you can see it's just printing the name of the balance.
Here's the print for a checking account,
you can see it's printing out checking account, name and balance.
Here's the print for the savings account, which is printing savings account,
the name, the balance and the interest rate.
And finally, for the trust account,
it's printing out the name, the balance, the interest rate and the number of withdrawals on that account.
That's it. Before we had that trust account Leo
and it only printed account Leo 10000.
Now we've got dynamic binding, so we should get what we want. So let's give this a run,
and that's exactly what happens. That's pretty cool. Now we've got trust account Leo
1000 2.6% interest rate and 0 withdrawals.
All right. So we're almost done.
The last step is to deal with those functions in account util
and clean that up, and we had a lot of duplicated code in there.
Once we've got that, then challenge is done.