Every
subclass of Window
should implement its own DrawWindow( )
method—but nothing requires that it do so. To
require subclasses to implement a method of their base, you need to
designate that method as abstract.
An abstract method has no implementation. It creates a method name and signature that must be implemented in all derived classes. Furthermore, making one or more methods of any class abstract has the side effect of making the class abstract.
Abstract classes establish a base for derived classes, but it is not legal to instantiate an object of an abstract class. Once you declare a method to be abstract, you prohibit the creation of any instances of that class.
Thus, if you were to designate DrawWindow( )
as
abstract
in the Window
class,
you could derive from Window
, but you could not
create any Window
objects. Each derived class
would have to implement DrawWindow( )
. If the
derived class failed to implement the abstract method, that class
would also be abstract, and again no instances would be possible.
Designating a method as abstract
is accomplished
by placing the keyword abstract
at the beginning of the method definition, as follows:
abstract public void DrawWindow( );
(Because the method can have no implementation, there are no braces; only a semicolon.)
If one or more methods are abstract, the class definition must also
be marked abstract
, as in the following:
abstract public class Window
Example 5-3 illustrates the creation of an abstract
Window
class and an abstract DrawWindow( )
method.
Example 5-3. Using an abstract method and class
using System;abstract public class Window
{ // constructor takes two integers to // fix location on the console public Window(int top, int left) { this.top = top; this.left = left; } // simulates drawing the window // notice: no implementationabstract public void DrawWindow( );
// these members are private and thus invisible // to derived class methods. We'll examine this // later in the chapter protected int top; protected int left; } // ListBox derives from Window public class ListBox : Window { // constructor adds a parameter public ListBox( int top, int left, string contents): base(top, left) // call base constructor { listBoxContents = contents; } // an overridden version implementing the // abstract methodpublic override void DrawWindow( )
{
Console.WriteLine ("Writing string to the listbox: {0}",
listBoxContents);
}
private string listBoxContents; // new member variable } public class Button : Window { public Button( int top, int left): base(top, left) { } // implement the abstract methodpublic override void DrawWindow( )
{
Console.WriteLine("Drawing a button at {0}, {1} ",
top, left);
}
} public class Tester { static void Main( ) { Window[] winArray = new Window[3]; winArray[0] = new ListBox(1,2,"First List Box"); winArray[1] = new ListBox(3,4,"Second List Box"); winArray[2] = new Button(5,6); for (int i = 0;i < 3; i++) { winArray[i].DrawWindow( ); } } }
In Example 5-3, the Window
class
has been declared abstract and therefore cannot be instantiated. If
you replace the first array member:
winArray[0] = new ListBox(1,2,"First List Box");
with this code:
winArray[0] = new Window(1,2);
the program will generate the following error:
Cannot create an instance of the abstract class or interface 'Window'
You can instantiate the ListBox
and
Button
objects because these classes override the
abstract method, thus making the classes
concrete
(i.e., not abstract).
Although designating DrawWindow( )
as abstract does force all the derived classes to
implement the method, this is a very limited solution to the problem.
If we derived a class from ListBox
(e.g.,
DropDownListBox
), nothing forces that derived
class to implement its own DrawWindow( )
method.
C++ programmers take note: in C# it is not
possible for Window.DrawWindow( )
to provide an
implementation, so we cannot take advantage of the common
DrawWindow( )
routines that might otherwise be
shared by the derived classes.
Finally, abstract classes should not just be an implementation trick; they should represent the idea of an abstraction that establishes a “contract” for all derived classes. In other words, abstract classes describe the public methods of the classes that will implement the abstraction.
The idea of an abstract Window
class ought to lay
out the common characteristics and behaviors of all
Windows
, even if we never intend to instantiate
the abstraction Window
itself.
The idea of an abstract class is implied in the word
“abstract.” It serves to implement the abstraction
“Window” that will be manifest in the various concrete
instances of Window,
such as browser window,
frame, button, list box, drop-down, and so forth. The abstract class
establishes what a Window
is, even though we never
intend to create a “Window” per se. An alternative to
using abstract
is to define an interface, as
described in Chapter 8.
The
obverse
side of the design coin from abstract is sealed
.
Although an abstract class is intended to be derived-from and to
provide a template for its subclasses to follow, a sealed class does
not allow classes to derive from it at all. The
sealed
keyword placed before the class declaration
precludes derivation. Classes are most often marked
sealed
to prevent accidental inheritance.
If the declaration of Window
in Example 5-3 is changed from abstract
to
sealed
(eliminating the
abstract
keyword from the DrawWindow( )
declaration as well), the program will fail to compile.
If you try to build this project, the compiler will return the
following error message:
'ListBox' cannot inherit from sealed class 'Window'
among many other complaints (such as that you cannot create a new protected member in a sealed class).
3.144.37.196