abstract Methods, Properties, Indexers, and Classes

   


abstract Methods, Properties, Indexers, and Classes

The Car class in Listing 16.3 of Chapter 16 contained a definition (shown next) for the MoveForward method that added 1 to the odometer variable.

 19:     public virtual void MoveForward() 20:     { 21:         Console.Write("Moving forward... "); 22:         odometer += 1; 23:         Console.WriteLine("Odometer reading: { 0} ", odometer); 24:     } 

However, as noted in the same section, MoveForward could mean anything in the generic Car class for which it was defined. The implementation of MoveForward in the Car class was merely meant to be a dummy implementation waiting to be overridden in the FamilyCar, SportsCar, and RacingCar classes where we had a better idea of how to implement it (FamilyCar is slow, SportsCar is medium fast, and RacingCar is very fast).

If we plant incorrect methods (like Car's MoveForward method) in our programs, we obviously face a serious problem. Anybody could just call this method and believe they were invoking a correct method.

We could attempt to eliminate this problem simply by removing the MoveForward method from Car and only implement it in the more specialized classes. However, this goes against our taxonomical class hierarchy and, even worse, it prevents us from using an important mechanism we will look at in a moment called polymorphism.

To solve our problem, C# allows us to specify a method to be abstract with the abstract keyword. An abstract method only contains the method header and no implementation. Instead, it requires a descendant to provide the implementation. As a result, we can throw away the dubious MoveForward implementation of the Car class and still express that any class derived from the Car class contains a MoveForward method. When a class contains one or more abstract methods, the class itself must be declared abstract. An abstract class cannot be instantiated because it contains methods that are not implemented.

Listing 17.1 provides a simple example of how an abstract method and an abstract class are defined. The source code is nearly identical to Listing 16.2 of Chapter 16, but this time MoveForward has been declared abstract in line 19 and the Car class declared abstract in line 3.

Listing 17.1 AbstractMoveForward.cs
01: using System; 02: 03: abstract class Car 04: { 05:     private uint odometer = 0; 06: 07:     protected uint Odometer 08:     { 09:         set 10:         { 11:             odometer = value; 12:         } 13:         get 14:         { 15:             return odometer; 16:         } 17:     } 18: 19:     public abstract void MoveForward(); 20: } 21: 22: class RacingCar : Car 23: { 24:     public override void MoveForward() 25:     { 26:         Console.Write("Moving dangerously fast forward... "); 27:         Odometer += 30; 28:         Console.WriteLine("Odometer in racing car: { 0} ", Odometer); 29:     } 30: } 31: 32: class FamilyCar : Car 33: { 34:     public override void MoveForward() 35:     { 36:         Console.Write("Moving slowly but safely forward..."); 37:         Odometer += 5; 38:         Console.WriteLine("Odometer in family car: { 0} ", Odometer); 39:     } 40: } 41:  42: class CarTester 43: { 44:     public static void Main() 45:     { 46:         RacingCar myRacingCar = new RacingCar(); 47:         FamilyCar myFamilyCar = new FamilyCar(); 48:         myRacingCar.MoveForward(); 49:         myFamilyCar.MoveForward(); 50:     } 51: } Moving dangerously fast forward... Odometer in racing car: 30 Moving slowly but safely forward...Odometer in family car: 5 

The combination of applying the abstract keyword (shown in line 19) and substituting the method body with a semicolon at the same time (positioned at the end of the line) is required to make MoveForward an abstract method. Because the Car class now contains an abstract method, it too must be declared abstract, as shown in line 3.

The way an abstract method is overridden in a derived class is identical to that of a virtual method. In fact, an abstract method is implicitly also a virtual method. Consequently, none of the code in the RacingCar or the FamilyCar classes needed to be changed from Listing 16.3 of Chapter 16 and, as you can see, the sample output is also unchanged. However, by making MoveForward and Car abstract, we cause a few important changes that are not revealed by our source code example. First, it is impossible to create an instance of the Car class, because an abstract class cannot be instantiated. Second, had we not overridden the MoveForward method in, say, the RacingCar class, but just inherited it untouched, RacingCar would have inherited MoveForward from Car. Because this MoveForward method is abstract, RacingCar would then contain an abstract method. This would oblige us to declare RacingCar abstract and thereby prevent it from being instantiated. Sometimes, several levels in a chain of derived classes consist of abstract classes for this same reason. This is legitimate and can easily be part of a superbly designed class hierarchy.

Note

graphics/common.gif

Even though we cannot instantiate an abstract class, we can still declare a variable to be of this type. For example, we could use our abstract Car class to make the following declaration:

 Car myCar; 

As you will see in a moment, this is an important ability needed to use polymorphism.


Non-abstract classes that can be instantiated are called concrete classes.

The get and set accessors of properties and indexers can also be declared abstract, with the same implications as those found for abstract methods. The syntax for declaring methods, properties, indexers, and classes abstract is shown in Syntax Box 17.1.

Syntax Box 17.1 Abstract Method

 Abstract_method::= [<Method_modifiers>] abstract <Return_type> <Method_identifier> (  graphics/ccc.gif[<Formal_parameter_list>] ); Abstract_property_1::=     [<Property_modifiers>] abstract <Return_type>  graphics/ccc.gif<Property_identifier>     {         [get;]         [set;]     } Abstract_indexer_1::=     [<Indexer_modifiers>] abstract [<Return_type>] this [<Parameter_list>] graphics/ccc.gif     {         [get;]         [set;]     } Abstract_class::=     <Class_modifiers> abstract <Class_name>     {         <Class_members>     } 

Notes:

  • An abstract method is declared with the abstract keyword. It does not have a method body, it has a semicolon after the two parentheses enclosing the formal parameter list instead. The following line provides an example:

     public abstract void MoveForward(); 
  • You can declare an entire property to be abstract by including the abstract keyword in the property header (Abstract_property_1). The get and set blocks must then be substituted by a semicolon as follows:

     public abstract int MyProperty {     get;     set; } 

    Both the get and the set accessors are now abstract.

  • abstract methods and accessors cannot also be declared private, static, or virtual.

  • An abstract method and accessor is implicitly virtual.

  • An abstract method and accessor can only reside inside an abstract class. On the other hand, an abstract class can contain non-abstract methods and accessors.

  • An abstract class cannot be instantiated.

  • If you derive a class from a class containing abstract methods, abstract accessors, or both, the derived class also becomes abstract unless you override and provide implementations for all the abstract methods and accessors inherited from the base class.

  • You can override a virtual method (or accessor) with an abstract method (or abstract accessor) in a derived class. Any classes derived from this abstract class must override these abstract methods and provide new implementations for them to become non-abstract.

The same rules for overriding a virtual method or accessor also apply for overriding an abstract method or accessor.

An overriding method must contain the same name, return type, and formal parameters (number and types) as the abstract method it is overriding. It also must include the override keyword and be declared with the same access modifier.

To make a property accessor overriding, you must include it in a property, whose header contains the override keyword. The following property contains both an overriding set and get accessor:

 protected override int Odometer {     set     {         <Statements>     }     get     {         <Statements>     } } 


   


C# Primer Plus
C Primer Plus (5th Edition)
ISBN: 0672326965
EAN: 2147483647
Year: 2000
Pages: 286
Authors: Stephen Prata

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net