12.4 Abstract Classes and Methods

When we think of a class type, we assume that apps will create objects of that type. In some cases, however, it’s useful to declare classes for which you never intend to instantiate objects. Such classes are called abstract classes. Because they’re used only as base classes in inheritance hierarchies, we refer to them as abstract base classes. These classes cannot be used to instantiate objects, because, as you’ll soon see, abstract classes are incomplete—derived classes must define the “missing pieces.” Section 12.5.1 demonstrates abstract classes.

Purpose of an Abstract Class

The purpose of an abstract class is primarily to provide an appropriate base class from which other classes can inherit, and thus share a common design. In the Shape hierarchy of Fig. 11.3, for example, derived classes inherit the notion of what it means to be a Shape—common attributes such as Location, Color and BorderThickness, and behaviors such as Draw, Move, Resize and ChangeColor. Classes that can be used to instantiate objects are called concrete classes. Such classes provide implementations of every method they declare (some of the implementations can be inherited). For example, we could derive concrete classes Circle, Square and Triangle from abstract base class TwoDimensionalShape. Similarly, we could derive concrete classes Sphere, Cube and Tetrahedron from abstract base class ThreeDimensionalShape. Abstract classes are too general to create real objects—they specify only what is common among derived classes. We need to be more specific before we can create objects. For example, if you send the Draw message to abstract class TwoDimensionalShape, the class knows that two-dimensional shapes should be drawable, but it does not know what specific shape to draw, so it cannot implement a real Draw method. Concrete classes provide the specifics needed to instantiate objects.

Client Code That Uses Only Abstract Base-Class Types

Not all inheritance hierarchies contain abstract classes. However, you’ll often write client code that uses only abstract base-class types to reduce client code’s dependencies on a range of specific derived-class types. For example, you can write a method with a parameter of an abstract base-class type. When called, such a method can be passed an object of any concrete class that directly or indirectly extends the abstract base class specified as the parameter’s type.

Multiple Levels of Abstract Base-Class Types in a Hierarchy

Abstract classes sometimes constitute several levels of the hierarchy. For example, the Shape hierarchy of Fig. 11.3 begins with abstract class Shape. On the next level of the hierarchy are two more abstract classes, TwoDimensionalShape and ThreeDimensionalShape. The next level of the hierarchy declares concrete classes for TwoDimensionalShapes (Circle, Square and Triangle) and for ThreeDimensionalShapes (Sphere, Cube and Tetrahedron).

Creating an Abstract Class

You make a class abstract by declaring it with the keyword abstract. An abstract class normally contains one or more abstract methods. An abstract method is one with keyword abstract in its declaration, as in

public abstract void Draw(); // abstract method

Abstract methods are implicitly virtual and do not provide implementations. A class that contains abstract methods must be declared as an abstract class even if it contains some concrete (non-abstract) methods. Each concrete derived class of an abstract base class also must provide concrete implementations of the base class’s abstract methods. We show an example of an abstract class with an abstract method in Fig. 12.4.

Abstract Properties

Properties also can be declared abstract or virtual, then overridden in derived classes with the override keyword, just like methods. This allows an abstract base class to specify common properties of its derived classes. Abstract property declarations have the form:

public abstract PropertyType MyProperty { get; set; }

The semicolons after the get and set keywords indicate that we provide no implementation for these accessors. An abstract property omits implementations for the get accessor and/or the set accessor. Concrete derived classes must provide implementations for every accessor declared in the abstract property. When both get and set accessors are specified, every concrete derived class must implement both. If one accessor is omitted, the derived class is not allowed to implement that accessor. Doing so causes a compilation error.

Constructors and static Methods Cannot be abstract or virtual

Constructors and static methods cannot be declared abstract or virtual. Constructors are not inherited, so such a constructor could never be implemented. Similarly, derived classes cannot override static methods, so such as static method could never be implemented.

Software Engineering Observation 12.4

An abstract class declares common attributes and behaviors of the various classes that inherit from it, either directly or indirectly, in a class hierarchy. An abstract class typically contains one or more abstract methods or properties that concrete derived classes must override. The instance variables, concrete methods and concrete properties of an abstract class are subject to the normal rules of inheritance.

 

Common Programming Error 12.1

Attempting to instantiate an object of an abstract class is a compilation error.

 

Common Programming Error 12.2

Failure to implement a base class’s abstract methods and properties in a derived class is a compilation error unless the derived class is also declared abstract.

Declaring Variables of Abstract Base-Class Types

Although we cannot instantiate objects of abstract base classes, you’ll soon see that we can use abstract base classes to declare variables that can hold references to objects of any concrete classes derived from those abstract classes. Apps typically use such variables to manipulate derived-class objects polymorphically. Also, you can use abstract base-class names to invoke static methods declared in those abstract base classes.

Polymorphism and Device Drivers

Polymorphism is particularly effective for implementing so-called layered software systems. In operating systems, for example, each different type of physical device could operate quite differently from the others. Even so, common commands can read or write data from and to the devices. For each device, the operating system uses a piece of software called a device driver to control all communication between the system and the device. The write message sent to a device-driver object needs to be interpreted specifically in the context of that driver and how it manipulates a specific device. However, the write call itself really is no different from the write to any other device in the system: Place some number of bytes from memory onto that device. An object-oriented operating system might use an abstract base class to provide an “interface” appropriate for all device drivers. Then, through inheritance from that abstract base class, derived classes are formed that all behave similarly. The device-driver methods are declared as abstract methods in the abstract base class. The implementations of these abstract methods are provided in the derived classes that correspond to the specific types of device drivers. New devices are always being developed, often long after the operating system has been released. When you buy a new device, it comes with a device driver provided by the device vendor. The device is immediately operational after you connect it to your computer and install the device driver. This is another elegant example of how polymorphism makes systems extensible.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset