baldwin.jpg

Programming with XNA Game Studio

Inheritance in C#

Learn how one class can extend another class and inherit all of the properties, events, and methods defined in that class and all of its superclasses; that even though a class may be extended into another class, it remains viable and can be instantiated in its own right; that inheritance is hierarchical with the overall hierarchy being rooted in a class named Object; that C# does not support multiple inheritance; about the ISA and HASA relationships.

Published: January 24, 2010
Validated with Amaya

By Richard G. Baldwin

XNA Programming Notes # 0108


Preface

General

XNA Game Studio 3.1
Note that all references to XNA in this lesson are references to version 3.1 or later.

This tutorial lesson is part of a continuing series dedicated to programming with the XNA Game Studio. I am writing this series of lessons primarily for the benefit of students enrolled in an introductory XNA game programming course that I teach. However, everyone is welcome to study and benefit from the lessons.

An earlier lesson titled Getting Started (see Resources) provided information on how to get started programming with Microsoft's XNA Game Studio. (See Baldwin's XNA programming website in Resources.)

The three main characteristics of an object-oriented program

Object-oriented programs exhibit three main characteristics:

I will explain and illustrate inheritance along with some related topics in this lesson.

Viewing tip

I recommend that you open another copy of this document in a separate browser window and use the following links to easily find and view the figures and listings while you are reading about them.

Figures

Listings

Supplemental material

I recommend that you also study the other lessons in my extensive collection of online programming tutorials.  You will find a consolidated index at www.DickBaldwin.com.

General background information

The first of the three major characteristics of an object-oriented program is encapsulation. I explained encapsulation in an earlier lesson. The second of the three is inheritance, followed by polymorphism.  I will explain inheritance in this lesson and will explain polymorphism in a future lesson.

A new class can extend an existing class

A class can be defined to inherit the properties, events, and methods of another class.  From a syntax viewpoint, this is accomplished using the : (colon) operator (see Listing 2).

The class being extended or inherited from is often called the base class or the superclass. The new class is often called the derived class or the subclass.

What is inherited?

The subclass inherits the data representation and behavior of the superclass (and all of its superclasses).  However, the subclass can modify the behavior of inherited methods by overriding them provided that they were declared virtual by the original author.  (That will be one of the topics in a future lesson on polymorphism.)   The subclass can also add new data representation and behavior that is unique to its own purposes.

The superclass remains viable

A program can instantiate objects of a superclass as well as of its subclass.  From a practical viewpoint, the superclass doesn't even know that it has been extended.

A hierarchy of classes

Inheritance is hierarchical. By that, I mean that a class may be the subclass of one (and only one) other class and may be the superclass of one or more other classes.

The overall inheritance hierarchy has a single root in the System.Object class. In other words, the System.Object class is the common ancestor for every other class.

Members of the System.Object class

The Object class defines the following eight methods, which are inherited by every other class:

Because these eight methods are inherited by every other class, they are always available for you to use in your code. (Possibly the most frequently used of these methods is the ToString method.)

The Button class

Moving down a single path in the inheritance hierarchy, we find that the family tree for the Button class in the System.Windows.Forms namespace is as follows:

If you were to examine the documentation for each of the classes in the Button class' family tree, you would probably find that each class is more specialized than its superclass. For example, the Object class is very generic and the Button class is very specialized. Generally speaking, classes become more specialized as you move down the hierarchy beginning with the Object class.

The Object class is the default superclass

When you define a new class, it becomes an immediate subclass of the Object class by default unless you cause your new class to extend some other class.

An orderly hierarchy

The C# inheritance mechanism allows you build an orderly hierarchy of classes to supplement the classes that are already in the class library. 

When several of your abstract data types have characteristics in common, you can design their commonalities into a single superclass and separate their unique characteristics into unique subclasses. This is one of the purposes of inheritance. 

The airship hierarchy

For example, suppose you are building a program dealing with airships. All airships have altitude and range properties in common. Therefore, you could build a base Airship class containing data and methods having to do with range and altitude.

From this superclass, you could derive a Balloon class and an Airplane class.

The Balloon class

The Balloon class might add properties and methods dealing with passenger capacity and what makes it go up (helium, hydrogen, or hot air). Objects of the Balloon class would then be able to deal with altitude, range, passenger capacity, and what makes it go up.

The Airplane class

The Airplane class might add properties and methods dealing with engine type (jet or propeller) and cargo capacity. Objects of the Airplane class could then deal with altitude, range, engine type, and cargo capacity.

Three types of objects

Having created this hierarchy of classes, you could instantiate objects of type Airship, Balloon, and Airplane with the objects of each type having properties and methods to deal with those special characteristics of the flying machine indicated by the name of the class.

From the general to the specialized

You may have noticed that in this hierarchical class structure, inheritance causes the structure to grow in a direction from most general to more specialized. This is typical.

Single and multiple inheritance

C++ and some other object-oriented programming languages allow for multiple inheritance. This means that a new class can extend more than one superclass. This has advantages in some cases, but can lead to difficulties in other cases.

C# does not support multiple inheritance. Instead it supports a different mechanism called an interface that provides most of the benefits of multiple inheritance without most of the problems.  I will explain the C# interface in a future lesson.

The ISA relationship

You will sometimes hear people speak of the ISA relationship when discussing OOP. The source of this terminology is more fundamental than you may at first suspect.

Object-oriented designers often strive to use inheritance to model relationships where a subclass "is a kind of" the superclass. For example, a car "is a kind of" vehicle. A programmer "is a kind of" employee which in turn "is a kind of" person. An airplane "is a kind of" airship and so is a hot-air balloon.

This relationship is called the ISA relationship. It's that simple.

The HASA relationship

If you were to define a class that more fully represents an airplane, you might choose to break certain parts of the airplane out into separate objects and to incorporate them by reference into your Airplane class.

For example, you might incorporate a Cockpit object, a LandingGear object, a Propeller object, etc. Then, (even though it wouldn't be good grammar), you could say than an object of your Airplane class "has a" Cockpit object, "has a" LandingGear object, etc. This is often referred to as a HASA relationship. For example, an airplane ISA airship and HASA cockpit.

Preview

The airship hierarchy

A little earlier I explained an airship hierarchy involving an Airship class, a Balloon class, and an Airplane class. I will present and explain a sample program that implements that hierarchy. The output from the program is shown in Figure 1.

Figure 1 Output from the program named Airship01.
Balloon
range = 5 miles
altitude = 500 feet
passenger capacity = 5
lift media = Hot Air

Airplane
range = 5000 miles
altitude = 35000 feet
cargo capacity = 20000 pounds
engine type = jet

Discussion and sample code

Will explain in fragments

I will explain this program in fragments. A complete listing of the program is provided in Listing 4 near the end of the lesson.

Four class definitions

This program consists of four class definitions:

The Airship class defines properties that are common to machines that fly:

The Balloon class extends the Airship class and defines properties that are peculiar to airships that are lighter than air:

The Airplane class extends the Airship class and defines properties that are peculiar to airplanes:

The Driver class instantiates objects of the Balloon class and the Airplane class and exercises their set and get methods.

The Airship class

Listing 1 shows the Airship class in its entirety.

Listing 1. The Airship class.

  //Define common properties in the base class.
  class Airship {
    private int rangeData = 0;
    private int altitudeData = 0;

    public int range {
      get {
        return rangeData;
      }//end get
      set {
        rangeData = value;
      }//end set
    }//end range property

    public int altitude {
      get {
        return altitudeData;
      }//end get
      set {
        altitudeData = value;
      }//end set
    }//end altitude property

  }//end class Airship

There is nothing in Listing 1 that you haven't seen in earlier lessons. This class provides set and get methods for two properties named range and altitude.

The Balloon class

Listing 2 shows the Balloon class in its entirety.

Listing 2. The Balloon class.

  //Define unique properties in the subclass.
  class Balloon : Airship {
    private int passengerCapacityData;
    private String liftMediaData;

    public int passengerCapacity {
      get {
        return passengerCapacityData;
      }//end get
      set {
        passengerCapacityData = value;
      }//end set
    }//end passengerCapacity property

    public String liftMedia {
      get {
        return liftMediaData;
      }//end get
      set {
        liftMediaData = value;
      }//end set
    }//end liftMedia property
  }//end Balloon class

The new material

The only thing in Listing 2 that is new to this lesson is the colon that is highlighted in yellow. This is the C# way of specifying that the class named Balloon extends or inherits from the class named Airship. In this case, the Balloon class is the subclass or derived class and the Airship class is the superclass or base class, depending on which flavor of jargon you prefer.

The effect of extending a class

The effect of having the Balloon class extend the Airship class is different from anything that you have seen in previous lessons. When one class extends another class, the new class inherits all of the properties, events, and methods of the superclass and all of its superclasses.

Airship extends Object

In this case, the Airship class extends the Object class by default. Therefore, an object instantiated from the Balloon class contains:

The beginning of the Driver class

At this point, I am going to show and explain the first half of the Driver class (see Listing 3) and relate it to the program output shown in Figure 1.

Listing 3. The beginning of the Driver class.

using System;namespace Airship01 {

  //Define a class to exercise the Balloon class and the
  // Airplane class.
  class Driver {
    static void Main(string[] args) {

      Balloon balloon = new Balloon();
      balloon.range = 5;
      balloon.altitude = 500;
      balloon.passengerCapacity = 5;
      balloon.liftMedia = "Hot Air";

      Console.WriteLine("Balloon");
      Console.WriteLine(
                   "range = " + balloon.range + " miles");
      Console.WriteLine(
              "altitude = " + balloon.altitude + " feet");
      Console.WriteLine("passenger capacity = " 
                             + balloon.passengerCapacity);
      Console.WriteLine("lift media = " 
                                     + balloon.liftMedia);

For convenience and because of their small sizes, I elected to define all four classes in the same file as the file that contains the Driver class with the Main method. That is not a requirement, however, and on large projects you may want to put each class definition in its own file.

Code common to all four classes

The code highlighted in yellow applies to all four classes. You have seen this before so it should not be new to you.

The Main method

The code highlighted in green is the beginning of the Main method.

Instantiate a new Balloon object

The code highlighted in white instantiates a new object of the Balloon class and saves its reference in a reference variable of type Balloon named balloon. This reference will be used later to access the new object.

Set properties in the Balloon object

The code highlighted in magenta calls the four set methods belonging to the new Balloon object, using them to set values into the four properties belonging to the Balloon object.

Remember that the set methods that hide two of the properties are defined in the Airship class and are inherited into the Balloon class. The other two set methods are defined in the Balloon class.

Get and display property values

The code highlighted in cyan calls the four get methods belonging to the new Balloon object, using them to get and display values from the four properties belonging to the new Balloon object.

Once again, the get methods that hide two of the properties are defined in the Airship class and are inherited into the Balloon class. The other two get methods are defined in the Balloon class.

The program output

The code in Listing 3 produces the first five lines of output text shown in Figure 1.

The remaining code

You can view the remaining code in the Driver class and the code in the Airplane class in Listing 4 near the end of the lesson. If you understand my explanation of Listing 1, Listing 2, and Listing 3 above, you should have no difficulty understanding the behavior of the code in the Airplane class and the remaining code in the Driver class.

No sharing of properties

There is an important point to remember, however. Even though the Balloon and Airplane classes each inherit the range and altitude properties from the Airship class, objects instantiated from the Balloon and Airplane classes do not physically share these two properties. Instead, each object has its own copy of the range property and its own copy of the altitude property. The only thing shared by the two objects is part of the blueprint from which each object is constructed.

Basically there is no sharing of anything among objects until the static keyword shows up and at that point, some sharing does take place. The use of the static keyword is a topic for a future lesson.

Run the program

I encourage you to copy the code from Listing 4.  Use that code to create a C# console project.  Compile and run the project.  Experiment with the code, making changes, and observing the results of your changes.  Make certain that you can explain why your changes behave as they do. 

Summary

In this lesson, you learned how one class can extend another class and inherit all of the properties, events, and methods defined in that class and all of its superclasses. You learned that even though a class may be extended into another class, it remains viable and can be instantiated in its own right. You learned that inheritance is hierarchical with the overall hierarchy being rooted in a class named Object. You learned that C# does not support multiple inheritance. You learned about the ISA and HASA relationships.

Complete program listing

A complete listing of the C# program discussed in this lesson is provided in Listing 4.

Listing 4. The program named Airship01.

/*Project Airship01
 * Illustrates inheritance
 * ******************************************************/

using System;

namespace Airship01 {

  //Define a class to exercise the Balloon class and the
  // Airplane class.
  class Driver {
    static void Main(string[] args) {
      Balloon balloon = new Balloon();
      balloon.range = 5;
      balloon.altitude = 500;
      balloon.passengerCapacity = 5;
      balloon.liftMedia = "Hot Air";

      Console.WriteLine("Balloon");
      Console.WriteLine(
                   "range = " + balloon.range + " miles");
      Console.WriteLine(
              "altitude = " + balloon.altitude + " feet");
      Console.WriteLine("passenger capacity = " 
                             + balloon.passengerCapacity);
      Console.WriteLine("lift media = " 
                                     + balloon.liftMedia);

      Airplane airplane = new Airplane();
      airplane.range = 5000;
      airplane.altitude = 35000;
      airplane.cargoCapacity = 20000;
      airplane.engineType = "jet";

      Console.WriteLine("");//blank line
      Console.WriteLine("Airplane");
      Console.WriteLine(
                  "range = " + airplane.range + " miles");
      Console.WriteLine(
             "altitude = " + airplane.altitude + " feet");
      Console.WriteLine("cargo capacity = " 
                    + airplane.cargoCapacity + " pounds");
      Console.WriteLine("engine type = " 
                                   + airplane.engineType);

      //Pause and wait for the user to press any key.
      Console.ReadKey();
    }//end Main
  }//end class Driver
  //====================================================//

  //Define common properties in the base class.
  class Airship {
    private int rangeData = 0;
    private int altitudeData = 0;

    public int range {
      get {
        return rangeData;
      }//end get
      set {
        rangeData = value;
      }//end set
    }//end range property

    public int altitude {
      get {
        return altitudeData;
      }//end get
      set {
        altitudeData = value;
      }//end set
    }//end altitude property

  }//end class Airship
  //====================================================//

  //Define unique properties in the subclass.
  class Balloon : Airship {
    private int passengerCapacityData;
    private String liftMediaData;

    public int passengerCapacity {
      get {
        return passengerCapacityData;
      }//end get
      set {
        passengerCapacityData = value;
      }//end set
    }//end passengerCapacity property

    public String liftMedia {
      get {
        return liftMediaData;
      }//end get
      set {
        liftMediaData = value;
      }//end set
    }//end liftMedia property
  }//end Balloon class
  //====================================================//

  //Define unique properties in the subclass.
  class Airplane : Airship {
    private int cargoCapacityData;
    private String engineTypeData;

    public int cargoCapacity {
      get {
        return cargoCapacityData;
      }//end get
      set {
        cargoCapacityData = value;
      }//end set
    }//end cargoCapacity property

    public String engineType {
      get {
        return engineTypeData;
      }//end get
      set {
        engineTypeData = value;
      }//end set
    }//end engineType property
  }//end Airplane class
  //====================================================//
}//end namespace Airship01


Copyright

Copyright 2009, Richard G. Baldwin.  Reproduction in whole or in part in any form or medium without express written permission from Richard Baldwin is prohibited.

About the author

Richard Baldwin is a college professor (at Austin Community College in Austin, TX) and private consultant whose primary focus is object-oriented programming using Java and other OOP languages.

Richard has participated in numerous consulting projects and he frequently provides onsite training at the high-tech companies located in and around Austin, Texas. He is the author of Baldwin's Programming Tutorials, which have gained a worldwide following among experienced and aspiring programmers.

In addition to his programming expertise, Richard has many years of practical experience in Digital Signal Processing (DSP). His first job after he earned his Bachelor's degree was doing DSP in the Seismic Research Department of Texas Instruments. (TI is still a world leader in DSP.) In the following years, he applied his programming and DSP expertise to other interesting areas including sonar and underwater acoustics.

Richard holds an MSEE degree from Southern Methodist University and has many years of experience in the application of computer technology to real-world problems.

Baldwin@DickBaldwin.com

-end-