Heads up! To view this whole video, sign in with your Courses account or enroll in your free 7-day trial. Sign In Enroll
Preview
Start a free Courses trial
to watch this video
Subclasses need the ability to override the behavior the base class. That's the purpose of the virtual keyword.
You might be interested to know that Alan Kay, one of the creators of OO, was a biologist by trade. The terms polymorphism and inheritance are both used in Biology.
In C# objects, we learned that
inheritance can be used to create an is
0:00
a relationship between two types.
0:05
For example,
map location is a type of point.
0:08
We subclass the point class
to create a new type of
0:12
point which we called map location.
0:15
Map location, by virtue that it inherits
from point, also has fields for
0:18
X and Y coordinates.
0:23
Objects often share many
of the same attributes and
0:26
behaviors as other types of objects.
0:29
A classic example is an animal.
0:32
All animals have similar
characteristics and behaviors.
0:35
For example, a defining characteristic
of all animals is the ability to move.
0:38
There are two types of animals,
vertebrates and invertebrates.
0:44
Vertebrates have backbones and
0:48
invertebrates don't, but
they're both still animals.
0:50
So, they can both move.
0:53
But, not all animals move in the same way.
0:55
Mammals and
0:58
birds are both types of vertebrates,
but they move quite differently.
0:59
In object oriented programming,
we also need the ability for
1:03
objects to behave differently based
on the type of object that they are.
1:07
This is called polymorphism.
1:11
And it's one of the core principles
of object oriented programming.
1:13
Let's see what this looks like in code.
1:17
Let's create a new type of invader.
1:21
First let's create a new file.
1:24
We will call our new invader
type shielded invader.
1:27
So we'll name this file
shielded invader.cs.
1:30
We'll copy the namespace and
class name from invader paste
1:35
it in shielded invader and
add the closing curly braces.
1:39
Instead of invader, we want our
class to be named shielded invader.
1:43
And we want it to inherit from invader.
1:47
We'll add a constructor that takes a path
parameter and all this constructor will do
1:51
is pass the path parameter up to
the constructor of the base class like so.
1:55
Now we have a new type of invader.
2:02
As the code stands right now,
2:04
shielded invader behaves exactly
like the original invader class.
2:06
That's because it inherits all of
the attributes and behaviors from invader.
2:11
Let's make it so
that when a shielded invader is hit,
2:16
there's a chance that it
won't sustain any damage.
2:20
For that we need to change the way
decrease health method works.
2:23
But wait, the decrease health method
is in the invader class definition.
2:27
We don't have it here in ShieldedInvader.
2:32
Let's take a look at the decrease
health method in invader.
2:34
When the decrease health method is called,
2:38
it will decrease the health of
the invader by the factor passed in.
2:40
This is exactly how we want it to work for
most invaders.
2:44
But if the invader is a shielded invader,
2:48
we don't always want to decrease the
health every time the method is called.
2:51
One way we could implement this
is to check if the current object
2:55
is an instance of shielded invader.
2:59
We can type, if(this is ShieldedInvader),
3:01
then do something here.
3:08
Else decrease health by
the factor passed in.
3:14
There are many problems with
writing code like this.
3:19
For one, it requires the invader class
to know about the other classes that
3:22
inherit from it.
3:26
This is not an extendable way to
add new types of invaders because
3:27
we have to change the invader class each
time we want to add a new type of invader.
3:31
Also, our elegant single line
method would end up being polluted
3:36
by code that doesn't directly have to
do with this specific type of invader.
3:41
We could eventually end up with a lot
of these if this is statements here.
3:45
The is operator is C#'s way of checking
to see if an object is of a certain type.
3:50
When I find myself tempted to write
a bunch of type checks like this,
3:56
it's a tell tale sign that I
should make the class polymorphic.
4:00
This means, making it so
that subclasses of this class can provide
4:04
their own implementations
of decreased health.
4:08
The word polymorphic
means to have many forms.
4:11
Just like how birds move differently,
4:15
shielded invaders should have
a different way to decrease help.
4:17
We can make it possible for subclasses
to provide their own implementation of
4:22
decreased health by adding the keyword
virtual to the method here.
4:26
Adding virtual is telling C# that this
is just one possible implementation of
4:31
the decrease health method and
4:35
subclasses can provide their own
implementations of this method.
4:37
Let's copy the declaration and
paste it in ShieldedInvader.
4:42
And we'll add the curly braces here.
4:46
Because this is a subclass, we need to
change the virtual here to override to
4:49
show that ShieldedInvader is overriding
the virtual method of the invader class.
4:53
In C# objects, we learned about the random
class and it can help us out here as well.
4:58
Let's create a static random instance in
the shielded invader and call it random.
5:04
Then in DecreaseHealth,
we'll say, if(random.Nextdouble
5:13
Is less than .5, Then call
5:22
the base classes DecreaseHealthMethod and
pass in the factor.
5:27
Next double returns a random
number between zero and one.
5:33
Because it is uniformly random,
half of the time,
5:36
this number will be less than 0.5.
5:40
So the body of this if statement will
only be executed 50% of the time.
5:42
Here we just call the base classes,
5:48
that is the normal invaders,
decrease health method.
5:50
We do this by typing base.
5:53
It's not enough to just
type decrease health,
5:56
because now there are two decrease
health methods that can be called.
5:59
We need to specify which
one we want called.
6:03
You should know that overridden methods
don't have to call the base classes
6:06
method.
6:10
We could have done something other
than call base.decrease health.
6:10
It just so happens that what we want
to do here is what is already done
6:14
in the base classes
decrease health method.
6:18
Now when towers attempt to decrease
the health of a shielded invader,
6:21
they will be successful only
half of the time on average.
6:25
Other than its implementation
of decrease health,
6:28
a shielded invader is exactly
like a normal invader.
6:31
We would not have wanted to write an
entirely new shielded invader class that
6:35
was just a copy of most of
the code of the invader class.
6:40
Instead we're reusing most of
the functionality of the Invader class and
6:43
making one small alteration to
make the shielded Invader class.
6:48
The really neat thing about this
is that all of the code that is
6:53
already designed to work
with the based Invader type
6:56
will also work with the shielded Invader
type without making any changes.
6:59
A shielded invader is still an invader,
it's just been enhanced a bit.
7:04
So we can go to Game.cs and change one of
these invaders here to ShieldedInvader.
7:09
Notice that this is still
an array of invaders.
7:15
We don't have to change anything else.
7:19
These invaders get past the level which
knows about the base invader type.
7:21
There is no reference to
ShieldedInvader in here.
7:26
In the play method, these invaders
get passed through the towers
7:30
FireOnInvaders method.
7:33
See here again, there is no reference
to a shielded invader yet, but
7:37
all this code will still work.
7:41
When decrease health is
called on an invader,
7:43
that is a normal invader,
its health will be decreased.
7:46
However, if decreased health is
called on an invader that is actually
7:50
of type shielded invader,
it may or may not suffer damage.
7:54
To really see what's going on,
let's move this console output.
7:58
We'll reprint shot at and hit an invader
to the invaders decrease health method.
8:02
We could add a using system directive
to the top of the file, but
8:08
instead we'll just add
the namespace name here.
8:12
Now in
ShieldedInvader's DecreaseHealthMethod,
8:15
let's add some output here too.
8:19
If the shield block the shot,
8:21
we'll say System.Console.Writeline and
8:25
print (Shot at a shielded invader but
8:30
it sustained no damage.")
Let's compile this
8:34
to make sure that we didn't
introduce any compilation errors.
8:39
We'll say msc- out:TreeHouseDefense, *.cs.
8:48
Now let's run it to see what we get.
8:57
As you can see,
9:02
even though fire on invaders accepts an
array of the base invader type, we still
9:03
get different behavior when decreased
health is called on a shielded invader.
9:08
That's because
the DecreaseHealth method is
9:13
overridden in the shielded invader class.
9:16
You need to sign up for Treehouse in order to download course files.
Sign up