Lecture 05, 06 - Inheritance & Polymorphism
Lecture 05, 06 - Inheritance & Polymorphism
6 Framework
Chapter 6, 8 – Understanding
Inheritance and Polymorphism
Outline
• The basic mechanics of inheritance
• The second pillar of OOP: The details of inheritance
• Programming for Containment/Delegation
• The third pillar of OOP: C#’s polymorphic support
• Understanding base class/derived class casting rules
• The master parent class: System.Object
• Abstract class
• Interfaces
The basic mechanics of inheritance
• Code reuse comes in two flavors:
– containment/delegation model (the "has-a"
relationship)
– inheritance (the "is-a" relationship)
• The basic idea behind inheritance
– new classes can be created using existing classes
A simple base class
using System;
namespace BasicInheritance{
// A simple base class.
class Car{
public readonly int maxSpeed;
private int currSpeed;
public Car(int max){
maxSpeed = max;
}
public Car(){
maxSpeed = 55;
}
public int Speed{
get { return currSpeed; }
set{
currSpeed = value;
if (currSpeed > maxSpeed){
currSpeed = maxSpeed;
}
}
}
}
}
A simple base class
using System;
namespace BasicInheritance
{
class MainClass
{
static void Main(string[] args)
{
Console.WriteLine("***** Basic Inheritance *****\n");
// Make a Car object and set max speed.
Car myCar = new Car(80);
• Manager is an Employee
• SalesPerson is an Employee
• Manager and SalesPerson
inherit all the public members
of Employee
• In addition, they have their own
special properties too.
Employee.cs
using System;
namespace EmployeeApp
{
class Employee
{
// Field data.
private string empName;
// Properties!
public string Name
{
get { return empName; }
set
{
if (value.Length > 15)
Console.WriteLine("Error! Name length exceeds 15 characters!");
else
empName = value;
}
}
public int ID { get; set; }
public float Pay{ get; set; }
public int Age{ get; set; }
public string SSN{ get; }
Employee.cs
//constructors.
public Employee() { }
public Employee(string name, int id, float pay) : this(name, 0, id, pay, "") { }
public Employee(string name, int age, int id, float pay, string ssn)
{
Name = name;
ID = id;
Age = age;
Pay = pay;
SSN = ssn;
}
public void DisplayStats()
{
Console.WriteLine("Name: {0}", Name);
Console.WriteLine("ID: {0}", ID);
Console.WriteLine("Age: {0}", Age);
Console.WriteLine("Pay: {0}", Pay);
Console.WriteLine("SSN: {0}", SSN);
}
// Methods.
public void GiveBonus(float amount)
{
Pay += amount;
}
}
}
Manager.cs
using System;
namespace EmployeeApp
{
class Manager: Employee//A manager is also an Employee
{
//In addition, manager has a special field
public int StockOptions { get; set;}
}
}
SalesPerson.cs
using System;
namespace EmployeeApp
{
class SalesPerson : Employee //Sale person is also an employee
{
// Salespeople need to know their number of sales.
public int SalesNumber { get; set; }
}
}
Program.cs
using System;
namespace EmployeeApp
{
class MainClass
{
// Create a subclass object and access base class functionality.
static void Main(string[] args)
{
Console.WriteLine("***** The Employee Class Hierarchy *****\n");
SalesPerson fred = new SalesPerson();
fred.Age = 31;
fred.Name = "Fred";
fred.SalesNumber = 50;
Console.ReadLine();
}
}
}
Controlling Base Class Creation with
the base Keyword
• To create a Manager, we need to first create
an Employee
– We should use the base keyword for this case
Manager.cs
using System;
namespace EmployeeApp
{
class Manager : Employee//A manager is also an Employee
{
public Manager(string fullName, int age, int empID,float currPay, string ssn, int numbOfOpts)
: base(fullName, age, empID, currPay, ssn) //When creating manager, need to also create an Employee
{
// This property is defined by the Manager class.
StockOptions = numbOfOpts;
}
//This is a default constructor
public Manager(){}
public int StockOptions//In addition, manager has a special field
{
get;
set;
}
}
}
SalesPerson.cs
using System;
namespace EmployeeApp
{
class SalesPerson : Employee //Sale person is also an employee
{
// Salespeople need to know their number of sales.
public int SalesNumber { get; set; }
// As a general rule, all subclasses should explicitly call an appropriate
// base class constructor.
public SalesPerson(string fullName, int age, int empID, float currPay, string ssn, int numbOfSales)
: base(fullName, age, empID, currPay, ssn)
{
// This belongs with us!
SalesNumber = numbOfSales;
}
// Add back the default constructor
public SalesPerson()
{
}
}
}
Keeping Family Secrets: The protected
Keyword
• Public items
– Are directly accessible from anywhere
• Private items
– Can be accessed only by the class that has defined
them
• Protected items
– Can be accessed directly by any descendant
subclass
Adding a Sealed Class
using System; seal keyword doesn’t allow other
namespace EmployeeApp class to inherit from this class
{
sealed class PTSalesPerson : SalesPerson
{
public PTSalesPerson(string fullName, int age, int empID,
float currPay, string ssn, int numbOfSales)
: base(fullName, age, empID, currPay, ssn, numbOfSales)
{
}
// Assume other members here...
}
}
THE THIRD PILLAR OF OOP:
POLYMORPHIC SUPPORT
A case study
using System;
namespace EmployeeApp
{
class MainClass
{
// Create a subclass object and access base class functionality.
static void Main(string[] args)
{
Console.WriteLine("***** The Employee Class Hierarchy *****\n");
// Give each employee a bonus?
Manager chucky = new Manager("Chucky", 50, 92, 100000, "333-23-2322", 9000);
chucky.GiveBonus(300);
chucky.DisplayStats();
Console.WriteLine();
SalesPerson fran = new SalesPerson("Fran", 43, 93, 3000, "932-32-3232", 31);
fran.GiveBonus(200);
fran.DisplayStats();
Console.ReadLine();
}
}
}
namespace EmployeeApp
{
class MainClass
{
// Create a subclass object and access base class functionality.
static void Main(string[] args)
{
Console.WriteLine("***** The Employee Class Hierarchy *****\n");
// A better bonus system!
Manager chucky = new Manager("Chucky", 50, 92, 100000, "333-23-2322", 9000);
chucky.GiveBonus(300);
chucky.DisplayStats();
Console.WriteLine();
using System;
namespace EmployeeApp
{
class MainClass
{
// Create a subclass object and access base class functionality.
static void Main(string[] args)
{
//This is a compiled time error since we can't create an instance of an abstract class
Employee e = new Employee();
}
}
}
Understanding the abstract class
• When a class has been defined as an abstract base class
– It may define any number of abstract members
• Abstract members can be used
– To define member that does not supply a default
implementation
– Leaving the subclass to provide the implementation for the
member
• Every subclass must either
– Be an abstract class itself or
– Implement all the abstract methods from the base class
• This trait of OOP allows you to
– Build easily extendable and flexible software applications
The shapes hierarchy
Shape.cs
using System;
namespace Shapes
{
// The abstract base class of the hierarchy.
public abstract class Shape Default value (used if you
{
public string PetName { get; set; } don’t input the name)
public Shape(string name = "NoName")
{ PetName = name; }
namespace Shapes
{
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("***** Fun with Polymorphism *****\n");
}
Program.cs
using System;
namespace Shapes
{
class MainClass
{
public static void Main(string[] args)
{
//This calls the Draw() method of the ThreeDCircle.
ThreeDCircle o = new ThreeDCircle();
o.Draw();
//This calls the Draw() method of the Circle
Shape s1 = new Circle();
s1.Draw();
//This calls the Draw() method of the Circle class
Shape s2 = new ThreeDCircle();
s2.Draw();
Console.ReadLine();
}
}
}
Type casting
• Reference of a base type can point to subtype
object
– Object obj = new Employee();
• Reference of a subtype cannot point to base type
object
– Object obj = new Employee();
– Employee e = obj;//Error
• If you know the object is of a specific subtype you
can cast it specifically
– Object obj = new Employee();
– Employee e = (Employee) obj;//Correct
as keyword
• Type casting may lead to run-time error
– Object e = new Employee();
– Manager m = (Manager) e;//run-time error
• as keyword
– Cast from one type to another
– Returns null (instead of throwing exception)
incase of incompatible type
– Object e = new Employee();
– Manager m = (Manager) e; //returns null
is keyword
• is keyword to determine whether two items
are compatible
using System;
namespace EmployeeApp{
class MainClass{
static void Main(string[] args) {
Employee e1 = new Manager();
Employee e2 = new SalesPerson();
CheckEmployee(e1);
CheckEmployee(e2);
}
static void CheckEmployee(Employee e){
if(e is SalesPerson){
Console.WriteLine("Your sale number: " + ((SalesPerson)e).SalesNumber);
}
if(e is Manager){
Console.WriteLine("Your stock options: " + ((Manager)e).StockOptions);
}
}
}
}
The Master Parent Class:
System.Object
• Every type ultimately derives from a base class
named System.Object that defines
– a set of common members for every type in the
framework
– A class that does not explicitly define its parent,
the compiler automatically derives your type from
Object
INTERFACE TYPES
Understanding Interface Types
• It is a named set of abstract members
• I.e., interface expresses a behavior that a given
class or structure may choose to support (extend)
• A class or structure can support as many
interfaces as necessary
• E.g., to work with SQL, .NET provides set of
classes (SqlConnection, OleDbConnection, etc)
– But all of these need to implement IDbConnection
– To work with different DBMSs in a consistent way
Interface Types vs. Abstract Classes
• Abstract class
– It may define any number of abstract members
– It is also free to define any number of constructors, field data,
nonabstract members (with implementation), and so on
• Interface
– It contains only member declarations (definitions, not
implementations)
• Abstract class has one major limitation
– Only derived types support the members defined by the abstract class
• In larger software systems
– It is common to develop multiple class hierarchies that have no
common parent
– You have no way to configure types in different hierarchies to support
the same polymorphic interface using abstract class
Defining Custom Interfaces
Interfaces
• It is defined with interface keyword
• Its members never specify an access modifier
– They are all abstract and public implicitly
• It does not contain implementations of members
• It does not have data fields
• It can specify property prototypes
• It does not have constructors
• It can contain event and indexer (study later)
Implementing an Interface
IPointy Interface
using System;
namespace Shapes
{
public interface IPointy
{
int Points{get;}
}
}
Update Hexagon.cs
using System;
namespace Shapes
{
public class Hexagon : Shape, IPointy
{
public Hexagon()
{
}
public Hexagon(string name) : base(name)
{
}
//You must either override this method or mark this class as abstract
public override void Draw()
{
Console.WriteLine("Drawing {0} Hexagon", PetName);
}
public int Points
{
get
{
return 6;
}
}
}
}
Add Triangle.cs
using System;
namespace Shapes
{
public class Triangle : Shape, IPointy
{
public Triangle()
{
}
public Triangle(string name): base(name)
{}
public override void Draw()
{
Console.WriteLine("Drawing {0} the Triangle.", PetName);
}
public int Points{
get{
return 3;
}
}
}
}
Calling interface member
using System;
namespace Shapes
{
class MainClass
{
public static void Main(string[] args)
{
IPointy iPointy;
//Reference of inerface can point to object of its subtype
iPointy = new Hexagon();
Console.WriteLine("Hexagon points: {0}", iPointy.Points);
Console.ReadLine();
}
}
}
Multiple Inheritance with Interface
Types
• An interface can extend multiple base
interfaces
– To design some powerful and flexible abstractions
Multiple Inheritance with Interface
Types
// Multiple inheritance for interface types is a-okay.
interface IDrawable
{
void Draw();
}
interface IPrintable
{
void Print();
void Draw(); // <-- Note possible name clash here!
}