|
|
|
To keep these concepts fresh in your mind, answer the following questions, and then check your answers at the bottom. For best results as a memory tool, answer these questions a few hours after reading the original material. 1) Given the following block of code from a program... foreach (Animal animal in animalArray) { if (animal is Cat) ((Cat)animal).Meow(); else if (animal is Dog) ((Dog)animal).Bark(); else if (animal is Chicken) ((Chicken)animal).Cluck(); } ...how could the program be changed to better use inheritence and polymorphism? 2) A programmer creates a Formula base class, with an abstract function called Calculate(). Next, he creates a SquareRoot class which inherits from Formula, and implements Calculate() with the "overrides" keyword. However, the base definition of Calculate() accepts two doubles, whereas Formula's implementation of Calculate only accepts one double. Is this legal? 3) Why would we want to use the "private" keyword in a base class, instead of the "protected" keyword? 4) A programmer creates an Employee base class, with an abstract function called CalculateSalary(). Next, she creates a ContractEmployee class which inherits from Employee, and implements CalculateSalary(). Because there are several kinds of contractors at her business, she wants to create some additional classes which inherit from ContractEmployee. However, all contractor salaries are calculated the same way, so how can she ensure that a class which inherits from ContractEmployee won't change CalculateSalary()? Answers 1) Regardless of which animal type the loop is dealing with, it would appear that the goal is always to make the animal "speak". Therefore, the Animal class should be given a virtual Speak() method, which the child classes can then inherit and override as needed. This way, we can just call animal.Speak() in the for loop, and skip all of that type checking. 2) No. One of the main ideas in polymorphism is that you can use an inherited type in exactly the same manner that you can use the base type. If SquareRoot's Calculate() method requires different parameters than Formula's Calculate() method, then this would no longer work: you'd need to know whether an object was a Formula or a SquareRoot before knowing how many parameters Calculate() would accept. Of course, once you've provided a proper override in SquareRoot, you're welcome to write overloads for it within the same class... but again, those overloads still won't benefit from a polymorphic relationship with Formula, because you won't know they exist unless you already know that the object is a SqaureRoot. What if an inherited class needs more information than the original method's parameters offer? One approach is to design the inherited class so that you can supply it with any information it needs before making the call to the polymorphic method. In this solution, the original method is often written without any parameters at all, so that it completely relies on the rest of the class to gather the information it needs. Another approach is to make the parameters themselves inheritable classes! Take care with that approach, though, as it can add a lot of extra classes (and complexity) to your code. 3) A huge benefit from classes is encapsulation, right? It could be that the base class is encapsulating something very complex. So, we use "protected" on the few things that we might want inherited classes to tweak, and make everything else private. This allows the inherited classes to "customize" the base class's original abilities in a controlled manner, without risking that they'll screw up some integral part of the original class. 4) By using the keyword "sealed" in the ContractEmployee's implementation of CalculateSalary(), the programmer can guarentee that any classes which inherit from ContractEmployee will not be able to override CalculateSalary(). At the same time, classes are still permitted to inherit from ContractEmployee (becaues we didn't seal the class itself). |
|