Working with Inheritance

Inheritance is the process of deriving one type from another, which promotes code reuse and makes it possible to use the huge selection of classes already written for you in the FCL. For example, the class System. Windows .Forms.Form , which you can base your own windows on, is a huge class. When you derive your own classes from that class, you're free to customize that class as you like, adding buttons , list boxes, check boxes, menus , and so on. (If you're already familiar with inheritance in a language like C++, you might just want to skim this discussion for the "For C++ Programmers" sidebars to see how C# differs from C++ here.)

A major part of inheritance involves polymorphism . Polymorphism means that you can provide different implementations of a method in different classes, but can call them as members of the same object variable. For example, you have a class named Animal that you derive two classes from Mammal and Fish . These two classes can both implement a method named Breathe , which will be quite different because fish and mammals breathe differently. Nonetheless, with a little preparation, you can assign objects of both the Mammal and Fish classes to Animal variables , and when you call the Breathe method of those variables, the method of the correct class, Fish or Mammal , will be called.

Here's a simple inheritance example. We'll create a class (structs don't support inheritance) named Window that can serve as the base class for all kinds of other user interface elements, such as buttons, menus, list boxes, radio buttons, and so on. The Window class has one method, Open , which displays the message "Opening..." :

 
 public class Window {   private string openingMessage = "Opening...";   public void Open()   {    System.Console.WriteLine(openingMessage);   } } 

If you wanted to create a new class, Menu , which displays drop-down menus, you could base that class on the Window class to take advantage of the screen-handling power already built into the Window class. To derive the Menu class from the Window class, you use this syntax:

 
  public class Menu : Window  {     .     .     . } 

Deriving a new class this way means that the new class inherits all the non-private members of the base class, so Menu inherits the Open method of the base class Window . However, opening a menu works differently from opening a window , so we might also want to change how the Open method of the Menu class works. In this case, we'll create a new method named Open in the Menu class, which displays the message "Displaying items..." . Note that we use the new keyword (not the same as the new operator) to indicate that we want to redefine this method from the base class's version:

 
 public class Menu : Window {  private string openingMessage = "Displaying items...";   public new void Open()   {   System.Console.WriteLine(openingMessage);   }  } 

The new keyword hides an inherited member with the same signature; you use it to tell C# that you're intending to redefine a method from the base class, and that defining your new method with the same name and signature as a base class method is not a mistake.

FOR C++ PROGRAMMERS

You don't have to use the new keyword in C++ when redefining a method in a derived class this way. In C++, you simply override the base class method, but C# makes a distinction between redefining a method totally, which you do with new , and overriding it (that is, customizing it for the current class), which you do with the override keyword. (See the topic "Overriding Virtual Methods " later in this chapter for more information.)


Now when you create an object of the Window class and call the Open method, you'll see "Opening..." but when you create an object of the Menu class and call the Open method, you'll see "Displaying items..." . You can see the code in ch04_01.cs, Listing 4.1.

Listing 4.1 Using Inheritance (ch04_01.cs)
 public class ch04_01 {   public static void Main()   {  Window window = new Window();   window.Open();   Menu menu = new Menu();   menu.Open();  } } public class Window {   private string openingMessage = "Opening...";   public void Open()   {     System.Console.WriteLine(openingMessage);   } }  public class Menu : Window   {   private string openingMessage = "Displaying items...";   public new void Open()   {   System.Console.WriteLine(openingMessage);   }  } 

Here's what you see when you run ch04_01.cs, create new objects of the Window and Menu classes, and call their Open methods:

 
 C:\>ch04_01 Opening... Displaying items... 

If we hadn't redefined the Open method in the Menu class (using new or the virtual methods coming up in a few pages), calling Menu.Open would have called the Open method inherited from Window that is, Window.Open and this code would simply have displayed "Opening..." twice.

Using the Access Modifiers

When you derive classes, you have some options that will set the accessibility of members inherited from the base class. These are the access modifiers we saw in Chapter 3, "C# Object-Oriented Programming;" for example, because the Window class's Open method was declared as public , it automatically becomes a member of any class derived from Window , and can be called from objects of the derived class.

If Open was declared private , on the other hand, it's restricted to the Window class. You can't access it in classes derived from Window , or from Window objectsit's locked up tight in the Window class, for internal class use only.

Members declared protected , on the other hand, are available in the class where they're declared, and in classes derived from that class, but not outside those classes. For example, if we declared Open protected:

 
 public class Window {   private string openingMessage = "Opening...";  protected void Open()  {     System.Console.WriteLine(openingMessage);   } } 

you could call it in code in the Window class, and code in classes derived from Window like Menu , but not outside those classes. For example, if you created an object of this version of the Window class in the Main method, you could not call its Open method.

In C#, you can also declare members internal , which restricts them to the access in the same assembly. Or you can declare members internal protected , which limits access to the current assembly, or types derived from the current class.

Calling Base Class Methods

We defined a new version of Open in the Menu class, which hides the Open method in the base Window class. But what if you wanted to reach the now-hidden Open method of the base class? That base class method is still available in the Menu class as base.Open . The base keyword refers to the base class you've inherited from, and gives you access to the base class members, which can be redefined in the derived class. For example, you can see how to call Window.Open from Menu.Open in ch04_02.cs, Listing 4.2.

Listing 4.2 Calling a Base Class (ch04_02.cs)
 public class ch04_02 {   public static void Main()   {     Window window = new Window();     window.Open();     Menu menu = new Menu();     menu.Open();   } } public class Window {   private string openingMessage = "Opening...";   public void Open()   {     System.Console.WriteLine(openingMessage);   } } public class Menu : Window {  public new void Open()   {   base.Open();   }  } 

Here's what you see when you run ch04_02.cs:

 
 C:\>ch04_02 Opening... Opening... 

FOR C++ PROGRAMMERS

Note that the C# way of accessing base class members differs from the C++ way. In C++, you use the scope resolution operator ( :: ) and the base class name, for example: Window::Open() .


Calling Base Class Constructors

Classes can inherit members from their base classes, but they cannot inherit constructors, which means that it's up to you to define your own constructors in derived classes. On the other hand, you can pass data back to a base class constructor; to do that, you use the base keyword, passing this keyword the argument(s) your constructor was passed which you want passed to the base class's constructor. Here's what that looks like:

 
 public Menu(string message) : base(message) { } 

In this case, the message argument is passed to the base class's constructor ( assuming the base class has a constructor that takes one string argument). You can see a full example in ch04_03.cs, Listing 4.3, where we're passing the argument named message back to the Window class's constructor.

Listing 4.3 Calling Base Class Constructors (ch04_03.cs)
 public class ch04_03 {   public static void Main()   {  Menu menu = new Menu("Opening the menu...");  menu.Open();   } } public class Window {   protected string openingMessage = "Opening...";  public Window(string message)   {   openingMessage = message;   }  public void Open()   {     System.Console.WriteLine(openingMessage);   } } public class Menu : Window {  public Menu(string message) : base(message){}  public new void Open()   {     System.Console.WriteLine(openingMessage);   } } 

When you pass the argument message back to the Window class's constructor, C# will look for a constructor that takes a single string argument and call it. Here's what you see when you run ch04_03.cs. Note that the text the Menu object was created with was passed back to the Window class's constructor, storing it in the protected openingMessage field, which is displayed in the Menu object's Open method:

 
 C:\>ch04_03 Opening the menu... 

FOR C++ PROGRAMMERS

When you pass arguments to a base class constructor in C++, you don't have to use the keyword base .


MULTIPLE-ARGUMENT CONSTRUCTORS

If you pass multiple arguments to a constructor, you don't have to pass them all back to a base class constructor; you can pass only the ones you want to, like this: public Menu(string message, int t, float f) : base(message, t){} .




Microsoft Visual C#. NET 2003 Kick Start
Microsoft Visual C#.NET 2003 Kick Start
ISBN: 0672325470
EAN: 2147483647
Year: 2002
Pages: 181

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