Bummer! This is just a preview. You need to be signed in with a Basic account to view the entire video.
Virtual Methods9:20 with Jeremy McLain
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