Implementation inheritance                      
                                         
Inheritance is the second pillar of object-oriented programming.  The concept of inheritance is simple, but the
details are not.  Inheritance allows a new class to reuse the attributes and behaviors from another class.  The new
class is the
derived class. The existing class is the base class.  The derived class can accept the base class
behaviors as is or can modify and extend them.  Inheritance models an "Is-A" relationship.  You can read the
diagram below as "SalesPerson derives from Employee".  Or you can say, "SalesPerson
is a type of Employee".












The basic syntax for deriving a class is shown in the following example.  The colon (:) syntax is used to indicate
inheritance.  You can mark a class as sealed if it cannot be used as a base class.  Notice in the Main() method
below, the DerivedClass object is able to invoke members of the base class.

















Implementation Inheritance: A Complete Example
To demonstrate the inheritance constructs, you will implement the design below:































Over the course of this section, we will be adding additional functionality to the initial design.  As well, we will
refactor the code over time to illustrate additional concepts.


Implementing the Employee Base Class
Employee is responsible for things common to any type of employee.  This includes the properties Name and
SSN.  It also includes the ComputePay method. This is meaningless to Employee, but it is required for all
derived classes.  Walk through the code for the Employee class.  Note that it does not have a default constructor.
























}

Employee also has a ComputePay method.  Derived classes should implement ComputePay in a meaningful
way. In other words, derived classes will
override this method.  The virtual keyword is used to declare that
derived classes can override the method.  In this particular case, ComputePay is meaningless to the Employee
class, so its implementation simply returns 0.  You will see a better way to do this later when we examine
abstract methods.


// In the Employee class.
public virtual double ComputePay()
{
  return 0;
}



Many times you can implement meaningful default functionality in virtual base class methods.  In a derived
class, you can choose to inherit the existing functionality or override it to suit the derived class.  For example,
assume most employees get a fixed yearly bonus.  Most derived employee types can use the following default
implementation, while others may override it.


public virtual double GetYearlyBonus()
{
  return 1000.0;
}


Implementing the WageEmployee Class

Now derive a WageEmployee class from Employee.  


public class WageEmployee : Employee
{
  private double mWage;
  private double mHours;

  public WageEmployee(string name, string ssn)
     : base(name, ssn)
  {
     mWage = 10.5;
     mHours = 40;
  }

  public override double ComputePay()
  {
     return mWage * mHours;
  }
}


The only tricky part is the constructor.  When constructing a derived class (WageEmployee), the runtime has to
construct the base class (Employee) first.  Unless you tell it otherwise, the runtime uses the default constructor
to construct the base class.  In this case, Employee is NOT the default constructor. Therefore, you must use the
base keyword to explicitly call the custom constructor.

Here is an example showing how to use these two classes:


class EmployeeMain
{
 static void Main(string[] args)
 {
   Employee emp = new Employee("Homer", "333-33-3333");
   WageEmployee wage = new WageEmployee("Marge", "444-44-4444");

   // Just to illustrate that we have inherited the Name property.

   wage.Name = "Bart";
 
   Console.WriteLine("Employee: {0}", emp.ComputePay());
   Console.WriteLine("Wage:     {0}", wage.ComputePay());
   Console.ReadLine();
 }
}











Implementing the SalesEmployee Class

SalesEmployee derives from WageEmployee.


public class SalesEmployee : WageEmployee
{
  private double mSales;
  private double mCommission;

  public SalesEmployee(string name, string ssn)
     : base(name, ssn)
  {
     mSales = 10000;
     mCommission = 0.1;
  }
...
}


Now the ComputePay method gets more interesting.  The formula for sales employees is (wage * hours) +
commissions.  So here is your first try at SalesEmployee.ComputePay:


// In SalesEmployee class

public override double ComputePay()
{

  // Compile error! mWage and mHours are declared private!

  return (mWage * mHours) + (mSales * mCommission);
}


Inheritance honors the access modifiers given to class members.  Therefore, a derived class cannot directly
access private members of its base class.  However, the WageEmployee.CalculatePay implementation already
returns the wage multiplied by hours, so you can use that instead:


// In SalesEmployee class

public override double ComputePay()
{

  // Even though this compiles, when the code executes
  // you will see a stack overflow exception. Why?

  return ComputePay() + (mSales * mCommission);
}


You need to explicitly call the WageEmployee.ComputePay method. Otherwise, this will recursively call itself.


// In SalesEmployee class

public override double ComputePay()
{

  // Use the base keyword to call the WageEmployee's
  // ComputePay method.

  return base.ComputePay() + (mSales * mCommission);
}


Alternately, you could define the fields in WageEmployee as protected.  Protected members are visible to
derived classes only.  Keep the current implementation because it better preserves the concept of
encapsulation.  Now you can update Main() to try out the SalesEmployee class.


static void Main(string[] args)
{
  Employee emp = new Employee("Homer", "333-33-3333");
  WageEmployee wage = new WageEmployee("Marge", "444-44-4444");
  SalesEmployee sale = new SalesEmployee("Bart", "555-55-5555");

  // Just to illustrate that we have inherited the Name property.

  wage.Name = "Bart";

  Console.WriteLine("Employee: {0}", emp.ComputePay());
  Console.WriteLine("Wage:     {0}", wage.ComputePay());
  Console.WriteLine("Sale:     {0}", sale.ComputePay());

  Console.ReadLine();
}












Implementing the Manager class

Finally, the Manager class derives from Employee.


public class Manager : Employee
{
  private double mSalary;

  public Manager(string name, string ssn)
     : base(name, ssn)
  { mSalary = 3000; }

  public override double ComputePay()
  { return mSalary; }
}


Meanwhile, back in the Main() procedure …


static void Main(string[] args)
{
  Employee emp = new Employee("Homer", "333-33-3333");
  WageEmployee wage = new WageEmployee("Marge", "444-44-4444");
  SalesEmployee sale = new SalesEmployee("Bart", "555-55-5555");
  Manager manager = new Manager("Maggie", "777-77-7777");

  // Just to illustrate that we have inherited the Name property.

  wage.Name = "Bart";

  Console.WriteLine("Employee: {0}", emp.ComputePay());
  Console.WriteLine("Wage:     {0}", wage.ComputePay());
  Console.WriteLine("Sale:     {0}", sale.ComputePay());
  Console.WriteLine("Manager:  {0}", manager.ComputePay());
  Console.ReadLine();
}












Abstract Methods and Classes

Currently, Employee.ComputePay simply returns zero.  The Employee class was never intended to implement
ComputePay.  Instead, derived classes should override it.  In this situation, it is usually a good idea to mark the
method with the
abstract modifier. This forces derived classes to override it.  The class declaring the abstract
method cannot implement the method.


public abstract class Employee
{
 public
abstract double ComputePay();
...
}


A class containing one or more abstract methods must also be marked as abstract.  An abstract class cannot be
used to instantiate an object.  An abstract class can only be used as a base class or to define a reference variable.


Employee emp; //<-- This is OK!

// Compile error! Abstract classes cannot be instantiated.

emp = new Employee("Homer", "333-33-3333");


If a derived class does not override an abstract member, then it is also abstract and must be marked with the
abstract modifier.


// Compile error! PartTimer must be abstract because it does
// not override Employee.ComputePay().

public class PartTimer : Employee
{
}


Question: If you cannot instantiate an abstract class, what is the point?  Answer: It provides a polymorphic
interface.  To explain this term, consider the following function:


static double ComputePayroll(Employee[] staff)
{
  double result = 0;
  for(int i = 0; i < staff.Length; i++)
  {
     result += staff[i].ComputePay();
  }
  return result;
}


Update Main() to call the ComputePayroll function:


static void Main(string[] args)
{
...

  Employee[] staff = new Employee[3];
  staff[0] = wage;
  staff[1] = sale;
  staff[2] = manager;

  Console.WriteLine("Payroll: {0}", ComputePayroll(staff));
  Console.ReadLine();
}


































































































































Inheritance
Table of Contents
C# Tutorial | C#.NET Tutorial | Inheritance Tutorial

Copyright (c) 2008.  Intertech, Inc. All Rights Reserved.  This information is to be used
exclusively as an online learning aid.  Any attempts to copy, reproduce, or use for training is
strictly prohibited.
Courseware
Training Resources
Tutorials
Services