OK, so we're kind of continuing on with the inheritance thing, but moving on to the next step.
So this next step is something called polymorphism, and I'm kind of going to get into the topic by
using an example with some very simple inheritance.
And then we're going to kind of build upon that and I'm going to explain this topic of polymorphism.
So let's take a look at the code base I have here already.
So it's basically just a simple shape project, very bare bones using some inheritance or stuff you've
seen before.
We have a shape class here, the access, our base class.
It has a constructor where you composite a color and an X and Y coordinate.
It has a set color, a color area and a type.
I'm going to go ahead and move these.
This virtual has to do with.
What I want to do first is just kind of explain this inheritance situation, so we have area and type.
So the area and type are also used by the derived classes, so if we go in here, this rectangle it
inherits from the base class shape.
And it has its own area and its own type.
One thing that you might have not seen syntax wise, is this initialization list constructor syntax
here.
I'm actually calling the shape base class right here, and I'm passing the color in the X in the way.
And why am I doing that?
Well, because all of the rectangle, the triangle and circle and shape, they share these attributes
like color and X coordinate and Y coordinate.
So that's why we're just going to use the base class to hold those values and we'll still have access
to them if we want right because I put protected here.
So that will make it so the drive classes have access to it.
So let's take a look at Triangle is pretty much the same thing I call the base class constructor here
in the Triangle Constructor and then it has a base and the height they're all having their own version
of area, right?
And they're all having their own version of type, which is returns a string, which is whatever type
the shape is.
This is base times height divided by two because it's basically a right triangle, even though I'd call
it triangle.
If you go to circle, it's just doing PR squared here for the area and it returns a circle because it's
a circle, right?
Notice that this Circle Constructor is also calling the base class constructor shape.
And the only other thing we really have is radio, so these are all like really bare bones.
Another thing you might notice is I'm implementing everything in the header files, so I'm not even
using CPP implementation files.
The only CPP file I have with that extension is actually just the client file may not keep the rest.
I can just put in the header file.
So this is totally possible.
You can just put them in the header file if you would like you noticed that I have like implementations
between the curly brackets here and the initialization list as well for the constructor and like I pointed
out already.
So if I go over to Main, what I'm doing is I'm explicitly instantiating each one of these classes the
the base class and then the three drive class with rectangle triangle and circle appropriately.
So then all I do is I use ASCII color, for example, for shape and type and area.
I do that for every one of the shapes, the base class and the three derived class shapes.
And notice that these are just not intimately allocated or anything.
They're just all like on the stack.
They're just being instantiated here in this mean function, normally without pointers or anything like
that.
So all stuff that you've seen before, right?
Pretty basic, so where does the polymorphism come in?
Well, let's go ahead and run this right now.
So everything looks good, right?
I'm able to print this stuff out and says that there's a shape with area zero red rectangle with area
of line, yellow triangle area above and circle with area.
So if I go to save, you might be wondering, Well, why did you even put area and type in shape if
we don't really know what the area of some ambiguous shape is?
Is this base class and some type of like, you know, what is the actual type?
It's just not having a type, it's a shape.
So you might want to put these things in a base class for a design purpose.
So sometimes it's good to kind of making designing a program with this base class in mind.
Well, one of my drive classes is going to be like, this is a blatant is a relationship, right?
Like a rectangle is a shape, a triangle is a shape, a circle is a shape.
So you might be wanting to kind of set this class as a scaffolding for the derived classes.
And so that kind of leads into the discussion of this polymorphism thing, so what is polymorphism even
meet?
Well, polymorphism means taking like one thing, taking many forms.
And so in this specific, intense instance, it means like a shape can have many forms.
And even more specifically.
A shape could have, you know, could different shapes could share the same methods, but like shape
at any time might have different implementations of those methods.
So that's like code white, what code way is what we're trying to do?
And we're kind of doing accomplishing that right here, right?
Like.
These all have their own versions of area, and they're all being called right.
But what if I wanted to just say, well, do I have to explicitly call these rectangle triangle circle?
Aren't they all shapes?
Can I just say that these are all shapes?
Maybe I had some sort of program where I was just making like a bunch of different shapes, and I just
wanted it to automatically resolve which type of shape it was, even though I said that the data type
was shape.
Maybe if I use these constructors, it will know automatically which type of shape it is and it will
call the right area method in the right area, the right type method.
So when I say method, I really mean the member function, right?
No function.
So hopefully it'll call the right area and type.
As you can probably guess, this might, you know, this is probably not going to work as you can see
that it's getting great out, it says functional area hides a non virtual function from class shape.
So they're not even really being used.
So is this functional area is never used.
So let's see what happens when we run this code now.
So look at the output now, it actually just calls all of these a shape.
And then it says the area is zero, so it's pretty obvious that what it's doing is that even though
we call these constructors, when we get down here, it's actually just only using this area in this
type from the base class, it's not able to resolve it to know which type of shape it really is.
So how would we make that happen?
Well, something that we could do is.
I'll go back here to the shape.
You are kind of already saw this because I left it there.
But what we can do syntax wise to kind of enforce this polymorphism is to put the word virtual in front
of these methods.
So if I put the keyword virtual, what it does is basically let the C++ compiler know which method to
use.
So when I put virtual on the base class, when rectangle inherits from shape and triangle and circle
as well, it's going to automatically and it actually calls this bindings, going to automatically bind
the correct method to the object based on the type at the time when it's like during runtime you.
But if the compile time, it kind of make that connection, that binding connection.
So.
It's pretty cool.
You can just add this one word.
Let's go ahead and change Maine, though, so one thing that we have to do is what I'm going to change
up here is I'm going to actually make these pointers.
So I'm going to say shape star se equals new shape.
Equals new rectangle, so why make these dynamically allocated now?
And I'm going to have to change these two points, right?
So kind of, you know, it was me here is painfully slow at this.
So essentially what we're doing is we are now just making it a shape pointer.
But what's happening is these constructors are getting called and it's actually dynamically allocating
memory for these types.
But we're saying that the point in time is shape, but the fact that we put that virtual keyword is
going to make us able to actually use the correct area and Typekit member functions for the correct
objects right that we made.
Even though we said that the type that's being pointed to where the pointer is, it can dynamically
allocated shape.
It's actually going to be able to resolve it because of the virtual keyword, and it's going to know
that each one of these are actually rectangle, triangle and circle.
So let's go ahead and run this.
And look at that, he was actually able to resolve them, so we're back to what we saw before, when
we explicitly put tape, rectangle and triangle and tight circle here.
So pretty cool, right?
All we had to do was we kind of changed things over to pointers, but we call them shape.
And then we went in here and we put virtual in front of these functions.
So I'm not going to go into too much more detail in this lesson, but in the next one, we will get
into kind of more polymorphism and really using this as a base class, that's just like a structural
thing, like it's just a scaffolding for the rest of the classes.
We're actually going to make it so we don't even instantiate shape.
We don't even make a shape object.
We're just going to design our program around a shape, and we're actually going to have these virtual
front functions, which are going to be pure virtual functions, and it'll force us to have to implement
those virtual functions in all these classes no matter what.
But what that does is it just kind of enforces good design and the idea of polymorphism, you know,
one thing taking many forms is a pivotal part of object oriented programming, and it's kind of nice.
You may be thinking, Well, why don't you just explicitly put rectangle triangle circle?
And the cool thing is just, you know, it makes it easier for every developer is doing the client side
code.
You can just call it a shape and you can make whatever one of these types of shapes that you want.
Maybe you have some type of like loop and you're making like multiple shapes.
You have some logic or something.
Well, it's a lot easier to just kind of have pointers, all of the same type, and the cool thing is
is that let's say you made a point sheep type.
You could just basically refer to the address of any other object, know any subtype like any derived
class.
And it would be totally fine to assign that memory to a sheep pointer that already makes it a lot more
flexible on the client side, right?
So it does have its use cases, and it's a very important part of API in general.
So not a lot change, right?
We still use the inheritance polymorphism as kind of, you know, goes hand in hand with inheritance.
The fact that we have a base class and the right classes is a really important part of polymorphism.
So since we have this base class available, we were able to make these virtual functions that are then
implemented differently across all of these rectangles.
And even though they're implemented differently, we were able to still have a shape pointer to all
of these and have it resolved the correct method to call it.
OK, so with that, I will leave it in this lecture and in the next lecture, we will go over abstract
base classes and spiritual functions for polymorphism.