In C#, the specialization relationship is typically implemented using inheritance. This is not the only way to implement specialization, but it is the most common and most natural way to implement this relationship.
Saying that ListBox
inherits from (or derives
from) Window
indicates that it specializes
Window
. Window
is referred to
as the base
class, and ListBox
is referred to as the
derived
class. That is,
ListBox
derives its characteristics and behaviors
from Window
and then specializes to its own
particular needs.
In C#, you create a derived class by adding a colon after the name of the derived class, followed by the name of the base class:
public class ListBox : Window
This code declares a new class, ListBox
, that
derives from Window
. You can read the colon as
“derives from.”
The derived class inherits all the members of the base class, both
member variables and methods. The derived class is free to implement
its own version of a base class method. It does so by marking the new
method with the keyword new
. (The
new
keyword is also discussed in in this
chapter.) This indicates that the derived class has in Section 5.3.3 later in this
chapter.) This indicates that the derived class has intentionally
hidden and replaced the base class method, as used in Example 5-1.
Example 5-1. Using a derived class
using System;
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
public void DrawWindow( )
{
Console.WriteLine("Drawing Window at {0}, {1}",
top, left);
}
// these members are private and thus invisible
// to derived class methods; we'll examine this
// later in the chapter
private int top;
private int left;
}
// ListBox derives from Window
public class ListBox : Window
{
// constructor adds a parameter
public ListBox(
int top,
int left,
string theContents):
base(top, left) // call base constructor
{
mListBoxContents = theContents;
}
// a new version (note keyword) because in the
// derived method we change the behavior
public new void DrawWindow( )
{
base.DrawWindow( ); // invoke the base method
Console.WriteLine ("Writing string to the listbox: {0}",
mListBoxContents);
}
private string mListBoxContents; // new member variable
}
public class Tester
{
public static void Main( )
{
// create a base instance
Window w = new Window(5,10);
w.DrawWindow( );
// create a derived instance
ListBox lb = new ListBox(20,30,"Hello world");
lb.DrawWindow( );
}
}
Output:
Drawing Window at 5, 10
Drawing Window at 20, 30
Writing string to the listbox: Hello world
Example 5-1 starts with the declaration of the base
class Window
. This class implements a constructor
and a simple DrawWindow
method. There are two
private member variables, top
and
left
.
In
Example 5-1, the new
class ListBox
derives from
Window
and has its own constructor, which takes
three parameters. The ListBox
constructor invokes
the constructor of its parent by placing a
colon (:) after the parameter list and
then invoking the base class with the keyword
base
:
public ListBox(
int theTop,
int theLeft,
string theContents):
base(theTop, theLeft) // call base constructor
Because classes cannot inherit constructors, a derived class must implement its own constructor and can only make use of the constructor of its base class by calling it explicitly.
Also notice in Example 5-1 that ListBox implements a new version of DrawWindow( ):
public new void DrawWindow( )
The keyword new
here indicates that the programmer
is intentionally creating a new version of this method in the derived
class.
If the base class has an accessible default constructor, the derived
constructor is not required to invoke the base constructor
explicitly; instead, the default constructor is called implicitly.
However, if the base class does not have a default constructor, every
derived constructor must explicitly invoke one
of the base class constructors using the base
keyword.
As discussed in Chapter 4, if you do not declare a constructor of any kind, the compiler will create a default constructor for you. Whether you write it yourself or you use the one provided “by default” by the compiler, a default constructor is one that takes no parameters. Note, however, that once you do create a constructor of any kind (with or without parameters) the compiler does not create a default constructor for you.
In
Example 5-1, the
DrawWindow( )
method of ListBox
hides and replaces the base class method. When you call
DrawWindow( )
on an object of type
ListBox,
it is ListBox.DrawWindow( )
that will be invoked, not Window.DrawWindow( )
. Note, however, that ListBox.DrawWindow( )
can invoke the DrawWindow( )
method of
its base class with the code:
base.DrawWindow( ); // invoke the base method
(The keyword base
identifies the base class for
the current object.)
The visibility
of a class and its members can be restricted through the use of
access modifiers, such as public
,
private
, protected
,
internal
, and protected internal
. (See Chapter 4 for a
discussion of access modifiers.)
As you’ve seen, public
allows a member to be
accessed by the member methods of other classes, while
private
indicates that the member is visible only
to member methods of its own class. The protected
keyword extends visibility to methods of derived classes, while
internal
extends visibility to methods of any
class in the same
assembly
.[8]
The internal protected
keyword
pair allows access to members of the same assembly (internal)
or
derived classes (protected). You can
think of this designation as internal
or
protected
.
Classes as well as their members can be designated with any of these
accessibility levels. If a class member has a different access
designation than the class, the more restricted access applies. Thus,
if you define a class, myClass
, as follows:
public class myClass { // ... protected int myValue; }
the accessibility for myValue
is protected even
though the class itself is public. A public
class is one that is visible to any other class that
wishes to interact with it. Occasionally, classes are created that
exist only to help other classes in an assembly, and these classes
might be marked internal
rather than
public
.
[8] An assembly (discussed in Chapter 1), is the unit of sharing and reuse in the Common Language Runtime (a logical DLL). Typically, an assembly is a collection of physical files, held in a single directory, which includes all the resources (bitmaps, .gif files, etc.) required for an executable, along with the Intermediate Language (IL) and metadata for that program.
3.16.75.165