30
Appendix E Inheritance 11/14/2017 4:07:55 PM Page 1 Under construction CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, 2017) ============================================================== Fundamentals of Inheritance Go to: Section E.1 Introduction Section E.2 Inheriting from a Class Section E.3 Base Classes in the .NET Framework Section E.4 Inheriting Base Class Members Fields, Methods, Properties Section E.5 Encapsulation and Designing with Classes and Inheritance Section E.6 Inheritance and Constructors Section E.7 Polymorphism and Type Substitution Section E.8 Replacing Methods in a Derived Class Section E.9 -- Summary

CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Embed Size (px)

Citation preview

Page 1: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 1

Under construction

CIS 3309 - Lecture Set E - Classes

(Ver 15: November 13, 2017)

==============================================================

Fundamentals of Inheritance

Go to:

Section E.1 – Introduction Section E.2 – Inheriting from a Class Section E.3 – Base Classes in the .NET Framework Section E.4 – Inheriting Base Class Members – Fields, Methods, Properties Section E.5 – Encapsulation and Designing with Classes and Inheritance Section E.6 – Inheritance and Constructors Section E.7 – Polymorphism and Type Substitution Section E.8 – Replacing Methods in a Derived Class Section E.9 -- Summary

Page 2: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 2

E. 1 Introduction

{NOTE: I have attempted to convert these notes from VB to C#. If you find

vestiges of VB or C# errors, please let me know. Thanks. FLF} Inheritance is one of the most significant design features of OOP. Inheritance was made popular more than two decades ago by languages such as C++ and Smalltalk. Since then, new languages (e.g., Java, Objective C, C#.NET, VB .NET, Python) have come along and refined the features and syntax for using inheritance. The .NET Framework makes extensive use of inheritance.

The CTS relies heavily on inheritance. When you use the Windows Forms package, your new forms will inherit from an existing form-based class in the FCL.

When you use ASP.NET, your Web pages and Web services will inherit from preexisting classes in the FCL.

As a developer building applications or component libraries based on the .NET Framework, you will find that familiarity with inheritance is an absolute necessity.

Why Bother with inheritance? In fact, why bother with any higher-level language features, such as looping and decision structures, try-catch, methods, classes, etc?

The goal with all of these language features is to provide programmers with tools that are intended to make all aspects of software life-cycle, from design, to testing, coding, debugging, and maintenance, easier and more efficient (and less costly). It is generally agreed that software development using features found in most object-oriented languages should enable us to better model problem domain entities and processes, helping to improve the development process. Do we need these language features to develop our systems? No. Are they believed to be useful over the entire life-cycle of a software product? Many developers think they are.

Page 3: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 3

E.2 Inheriting from a Class Inheritance allows you to derive new classes from an existing ones, thereby avoiding duplication, and enabling us reuse and enhance existing software components as suggested for entities in a particular problem domain. Definitions (Terminology): Suppose that class C inherits from class B. Then class B is typically called the base class, and class C is called the derived class. (Some refer to B and C as superclass and subclass, or as parent and child classes, respectively. In this material, we will do our best to use the terms "base" and "derived." Contracts – It is useful to think of classes as describing a contract between a client (the class) and objects of the class. A derived class definition automatically inherits the contract of its base class.

Another kind of inheritance, inheritance by Specification is also important, but will not be discussed here.

One of the primary reasons for designing with inheritance is that it provides an effective means for reusing code. For example, you can define a set of fields (attributes), methods, and properties in one class, and then use inheritance to reuse this code across several other classes.

Inheritance is particularly beneficial in scenarios that require multiple classes with much in common but in which the classes are all specialized in slightly different ways. Examples include the following familiar categories: employees (person, administrative, technical, sales), database tables (customers, orders, products), cycles (bicycle, tricycle, unicycle, motorcycle), and graphical shapes (circle, rectangle, triangle).

Example 1: A simple base class

// Base class

public class Person

{

private string hiddenName; // Person's full name

private int hiddenAge; // Person's age

Inheritance by Specialization --

The idea is that the derived class starts with a reusable class definition and modifies it by adding more members or by changing the behavior of existing methods and properties.

Page 4: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 4

// No-argument constructor

public Person ()

{

hiddenName = ""; hiddenAge = 0;

} // end no-argument Constructor

// Parameterized constructor

public Person (string n, int a)

{

hiddenName = n; hiddenAge = a;

} // end parameterized constructor

. . .

// Private method that calculates the age of a person

private int CalculateAge()

{

int years;

// calculate the difference in years

years = DateTime.Now.Year - hiddenBirthDate.Year;

// subtract another year if we're before the

// birth day in the current year

if (DateTime.Now.Month < hiddenBirthDate.Month ||

(DateTime.Now.Month == hiddenBirthDate.Month &&

DateTime.Now.Day < hiddenBirthDate.Day))

years = years - 1;

return years;

} // end CalculateAge

} // end Person Class

End Class

Basic syntax of inheritance -- Example 1 (above) illustrates the basic syntax a class

named Person that we would like to use as a base class. In C#, when you want to

state explicitly that one class inherits from another, you follow the name of the class with a colon and the name of the base class. Below is an illustration of the basic syntax of

inheritance: a derived class definition for a Student using Person as its base class:

public class Student : Person

{

private string hiddenStudentID;

private string hiddenMajor;

. . .

// No-argument constructor

public Student()

{

hiddenStudentID = "";

Page 5: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 5

hiddenMajor = "";

} // end no-argument constructor

// Parameterized constructor (with 1 argument)

// Calls the base class first, passing it name

public Student (string name, int age): base (name, age)

{

hiddenStudentID = "";

hiddenMajor = "";

} // end parameterized constructor (with 2 arguments)

. . .

} // end Student Class

In this example,

The Person class serves as a base class for the Student class.

This Student class and any other classes derived from Person will always share

a common set of implementation details, and all will support a unified programming

contract defined by the Person class. (But it is also possible to write

implementations for these derived classes that are quite different from each other as well as to add new members to each class to further increase their specialization, as you will see as you proceed with your own project.)

By default, every class you create in C#.NET can be inherited by other classes. If for some reason you don't want other programmers to inherit from your class, you can create a sealed class. A sealed class is defined in the C# .NET language using the keyword

sealed. The compiler will generate a compile-time error whenever a programmer

attempts to define a class that inherits from such a sealed class:

// Sealed class definition public sealed class Programmer

{ // Sealed class implementation

. . .

} // End Class

public class Programmer : Genius // compile-time error!

Figure E.1 on the next page shows a design view of class definitions known as an inheritance hierarchy.

Page 6: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 6

Figure E.1 - An inheritance hierarchy

The Person class is located at the top of the hierarchy.

The Client and Employer classes inherit from the Person class and are

located directly below it in the inheritance hierarchy.

Notice the direction of the arrows when denoting inheritance.

Manager and Worker have been defined with Employee as their base class.

They inherit indirectly from the Person class. Thus a class in a multilevel inher-

itance hierarchy inherits from every class reachable by following the inheritance arrows upward.

For example, you can correctly say that a programmer "is a" person. You can also correctly say that a senior programmer "is a" programmer. The purpose of the “is-a” test is to ensure that a derived class is designed to model a more specialized version of whatever entity the base class is modeling. MODEL is the key term here!! All classes model something. And, virtually

everything we do in writing programs involves constructing models of processes and entities.

Person

Client Employee

Manager Worker

Design Rule –

Two classes that will be related through inheritance should be able to pass the is-a test.

-- If it makes sense to say "C is a B," then it makes sense for class C to inherit from class B.

-- If such a sentence doesn't make sense, then you should reconsider the use of inheritance in this situation.

Page 7: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 7

You should try never to establish an inheritance relationship between two classes that cannot pass the “is-a” test. Example 2: Suppose you have a cycle class hierarchy with a cycle at the top and a unicycle, bicycle and tricycle (remember those?) all inheriting from the cycle. It might be tempting now to put such items as wheels, tire, handlebars, etc., (also modeled using classes) somewhere in the hierarchy. You should resist this temptation! Wheels, tires, handlebars, etc., cannot pass the "is-a" test for any of the classes just discussed. The three items we just listed should be treated as additional attributes of the cycle entities. [You can correctly say that a bicycle "has a" wheel (or two), but that relationship calls for a different design technique that doesn't involve inheritance. When you determine that two entities exhibit the "has a" relationship, the situation most likely calls for a design using containment, in which the Wheel class (for example) is used to define fields (attributes) within the Bicycle class (for example). In other words, the Bicycle class would likely contain one or more wheel objects (instances of the Wheel class.]

E. 3 Base Classes in the .NET Framework Now that you've seen some basic principles and the syntax for using inheritance, it's time to introduce a few important rules that imposed by the .NET Common Type System (CTS).

Example 3: When you define a class without explicitly specifying a base class, the compiler automatically modifies the class definition to inherit from the Object class in the FCL. Thus, the following two class definitions have the same base class:

// Implicitly inherit from Object

public class Cat {}

// Explicitly inherit from Object

public class Cat : System.Object { }

Note that every structure and every enumeration also has a base type. Recall from our earlier study of data types that the inheritance hierarchy of the CTS is singly rooted because the system-defined Object class serves as the ultimate base type.

.NET Rules Governing the use of Inheritance -- 1. You cannot define a class that inherits directly from more

than one base class. (As is the case with Java and VB, CTS does not support multiple inheritance.)

2. You cannot define a class that doesn't have a base class.

Page 8: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 8

Every other class either inherits directly from the Object class or inherits from another class that inherits (either directly or indirectly) from the Object class.

E.4 Inheriting Base Class Members – Fields, Methods, Properties We begin by recalling the levels of class member accessibility discussed in a previous lecture set. These are summarized in the next box. Keeping these definitions in mind we can briefly summarize how inheritance works.

Every public or protected member (field, method, and property) that is part of a base class definition is inherited by the derived class definition.

Each object created from a derived type carries with it all the states and behaviors that are defined by its base class.

Code in a derived class has direct access to the public and protected members inherited from its base class. However, access to the private members of the base class must be programmed using the public methods in the base class.

Constructors are not inherited. We will have more to say about constructors in Section E.6. For now, we suggest that you always write at least a base constructor for all of your classes.

Five Levels of Accessibility -- Private. A base class member defined with the Private access modifier is not acces-sible to code outside this class. This no other class, derived or otherwise, can directly access this member. Protected. A base class member defined with the Protected access modifier is directly accessible to code inside the defining class and any other class derived from this class. But it is not accessible to any other class. Public. A base class member defined with the Public access modifier is directly accessible to code inside any class. Internal. A member that is defined with the Internal access modifier is accessible to all code inside the containing assembly but inaccessible to code in other assemblies. The internal level of accessibility is not affected by whether the accessing code is part of a derived class. Protected Internal. The protected internal level of accessibility is achieved by combining the Protected access modifier with the Internal access modifier. A protected internal is accessible to all code inside the containing assembly and to code within derived classes (whether the derived class is part of the same assembly or not). This is illustrated further in the case of Class F in Figure E.3 shown later.

Page 9: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 9

What Goes On Behind the Scenes? Constructors aside for now, one view of how inheritance works is depicted in Figure E.2. Figure E.2 – Visualizing a Base Class as Seen “Through” a Derived Class

As this figure shows, all members (methods and data stores) of the base class are inherited by the derived class (all depicted in the white squares). All rules of accessibility to these inherited base class members are the same as for the base class. Thus, the public and protected members of the base class are directly accessible to the derived class. The private members of the base class are still encapsulated and accessible ONLY through public methods of the base class. One way to view this is to consider the base class as “becoming part of” the derived class. Remember too, that the derived class may contain its own private, protected, public, etc. members (shown in yellow). In Figure E.2, we indicate this accessibility for

Derived Class

Public and Protected Additional Data Stores (if any)

Additional Methods

Private Hidden Additional Data Stores

Hidden Additional Methods (if any)

(Accessible ONLY to this derived

class)

Base Class

Private Hidden Base Data Stores

Hidden Base Methods

(if any) Not directly

accessible to derived class

Public and

Protected Base Class Data Stores (if

any)

Base Class Methods

(directly accessible to

derived class)

Page 10: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 10

both the derived and base classes using a dotted box to enclose public and protected class members. The private members of the base class, and any additional private members of the derived class, are accessible only through the use of inherited public methods of the base class. They are enclosed in solid line boxes. In the EmployeeManagerClient example illustrated in Figure E.1 this “becoming part of“ concept implies, for example, that the three attributes of a Person become part of a Manager object. Person may be an abstract class (which cannot be instantiated), but it does not have to be instantiated for its attributes to become part of a Manager object. However, these three attributes, can only be accessed according to the access rules shown in the Five Levels of Accessibility box shown previously. Thus, if the attributes of the Person class are private, which is what I generally prefer, they can only be accessed through the methods in the Person class. The following example and accompanying diagrams (see Figure E.2A – E.2C) illustrate

these points for a small code sample. Note that name and age are assumed to be

properties defined in the Person class even though they are not shown (You could

easily write them). Example 4: Inheritance and Access Modifiers – How it all works

public class Person

{ . . .

private string hiddenName;

private int hiddenAge;

// Parameterless constructor

public Person() {

hiddenName = "";

hiddenAge = 0;

} // end parameterless argument constructor

// Parameterized (Overloaded) constructor

public Person (string n, int a) {

hiddenName = n;

hiddenAge = a;

} // end parameterized constructor

public bool commitToDB() { . . .} // not a virtual method

} // end Class

(continued on next page )

Page 11: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 11

// Subclassing for Specialization

public class Borrower : Person

{

// Specialization - adding a new data store

// (not part of Person class)

private double hiddenCreditLimit;

public Borrower() {

// Call parameterless Person constructor here

hiddenCreditLimit = 0.0;

} // end parameterless constructor

public Borrower (string n, int a, double s) {

// Call the parameterized constructor here

// Pass it n and a.

hiddenCreditLimit = s;

} // end overloaded constructor

public bool new commitToDB() { // hides the parent version

. . .

} // end commitToDB

. . .

} // end Class

Figure E.2B provides another view of how all of this works, a view that is specific to the current example. It shows that all public and protected members of the base class (in our case, the class Person) are inherited in the derived class (in our case, the Borrower class). These derived class members are therefore visible to any user code in the same way as are the members of the base class. In addition, the derived class may contain its own private, protected, public, etc. members. Should there be any naming conflicts between a base class and a derived class, usually

caused by hidden or overridable (replaceable) functions such as commitToDB, we can

distinguish one member from another using the prefixes base and this. For example,

base.commitToDB()

used in the derived class Borrower represents a call the version of commitToDB

found in the base class Person. On the other hand

this.commitTODB() or simply commitToDb()

used in the derived class Borrower references the "current instance" of commitToDB

(found in the Borrower class) .

Page 12: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 12

Figures E.2 and E2.A illustrate the most important point about inheritance. To reiterate:

Figure E.2A – A Derived Class and Its Related Base Class

Figure E2.A Another Illustration of Inheritance

Person Object

Borrower

Object

Object

Hidden

Name

Hidden

Age

name

age

Hidden

Credit

Limit

creditLimit

toString

commitToDB

A public derived class inherits the data stores of the base class. It also inherits and possibly redefines the methods of the base class. Each object created from a derived type carries with it all the states and behaviors that are defined by its base class. New fields (attributes), properties, and methods may also be added in the derived class. The behaviors of the fields in the base class are not changed by the inheritance. So it is as though an object of the base class becomes a part of the derived class whenever an object of the derived class is instantiated.

commitToDB

Page 13: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 13

***** Skip this – go to End Skip 1 ***** Another way to illustrate this point is shown in Figure E.2B. As shown in this Figure, the

public properties age and name and the public method commitToDB are all inherited by

the Borrower derived class from the Person base class. Had there been any protected

members of the Person class, they too would have been similarly inherited by the

Borrower class. [Note that we obtained the list of accessible members in the Borrower

class simply by typing “borrower1.” following the declaration of a type borrower1

object in the code shown.] Remember that there is a replacement version of

commitToDB in the Borrower class and that all calls in this class to this method, if not

prefixed with base will refer automatically to the replacement function.

Figure E.2B – Inherited Public Members of a Derived Class (uses VB code)

Page 14: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 14

An examination of the class hierarchy constructed for the code shown for Example 4 also serves to illustrate this point (see Figure E.2C). These class hierarchies can be viewed by right clicking on the top (Project Line) in the Solution Explorer window and then selecting View Class Diagram from the window just opened. The top part of Figure E.2C

shows that class Borrower inherits from class Person. It also shows all the details of

the members of the class Person that are inherited as well as the details of the additional

members of the Borrower class defined in that class.

Figure E.2C – Class Hierarchy for Example E.4 Showing Members of Person Class

Page 15: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 15

Example 5: The meaning of access modifiers – A Graphic View

Figure E.3 illustrates the implications of using the different access modifiers in code involving numerous classes in two different assemblies.

Figure E.3 Five Levels of Accessibility – An Illustration

The following statements are all related to the Assemblies I and II and the class relationships illustrated in Figure E.3 below. These are a repeat of the Five Levels of Accessibility box shown earlier in this section, but they relate specifically to Figure E.3.

1. All private members of class A are accessible to none of the other classes in the figure (including even those that are derived from class A..

2. All protected members of class A are accessible to the classes derived from A, namely, classes B, C, and F (even though F is in a different Assembly).

3. All protected internal members of class A are accessible to derived classes inside Assembly I (classes B and C) but not to derived classes outside Assembly I (class F).

4. All public members of Class A are accessible to all other classes in the figure.

A

C B

D E

Classes used …

Assemblies used …

Assembly I

Assembly II

Classes used …

A, B, C, and F are part of one class hierarchy with base class A

G

Page 16: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 16

5. All public internal members of Class A are accessible everywhere (to all classes) in class A's Assembly but not outside this Assembly. Thus, such members are accessible to classes B, C, D, and E, but not to class G. Note the exception here: public internal members in classes A and C may be accessed in Class F even though F is in another assembly.

***** End Skip 1 Begin reading here again *****

E. 5 Encapsulation and Designing with Classes and Inheritance Encapsulation is the practice of hiding the implementation details of classes and assemblies from other code. Terms such as information hiding, and limiting the need to know are also used when referring to the concept of encapsulation and object-oriented design and programming. Low coupling and high cohesion are also terms used. For example,

A private member of a class, A, is hidden from ALL other classes in an application

A protected member of a class A is hidden from all other classes in an application other than those derived from A or its descendants

An internal member of a class A is hidden from code in other assemblies.

E. 6 Inheritance and Constructors (a bit complicated) The way in which constructors are handled isn't as obvious. Unless you want to delve into more of the constructor handling complexities, it might be easier to follow a few basic suggestions indicated in this section.

Bottom Line – Be as restrictive, keeping access to class members carefully

guarded. Be sure you have good reasons for loosening permission access.

Constructive Constructor Suggestions 1. Always write a no-argument (parameterless) constructor for every class you design. Do this even if you also write some parameterized constructors in the same class. 2. Your parameterless constructor can have no code body, but you might wish to use it to ensure that initializations of class variables (even just to blank or null strings, or 0 numeric values, etc.) are handled, even if no other initializations seem to be needed. 3. Make sure each constructor in a derived class calls its corresponding base class constructor before it sets about to do its own work. 4. It is true that the compiler will take care of some of these items for you, but it is best not to leave anything to chance. 5. It is also a good idea to ensure that all constructors are visible in each class, as opposed to simply generated by the compiler. 6. Parameterized constructors in a derived class do not need the same interface as in the base class, but if you are going to pass arguments through to the base class, these arguments must appear in the derived class as well. (See examples in Project IV code.)

Page 17: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 17

Remember that constructors in an inheritance hierarchy are not inherited. Furthermore, they must be executed in the reverse order. Thus in Figure E.3, any constructor in Class F must execute a constructor in Class C before carrying out its own work. In turn, the constructor in Class C must call a constructor in class A before carrying out its tasks. If you do not explicitly call these constructors in the order just described, the compiler will generate these calls for you. Remember:

1. If the derived class a parameterless constructor, the base class must also have a parameterless constructor.

2. Each constructor defined in a derived class must explicitly call one of the accessible constructors in its base class before performing any of its own initialization work.

Example 6: Consider the following class definition:

// A class you write

public class Dog {

. . .

} // end class Dog

Once compiled, the definition of this class might look something like this:

// Code generated by compiler

public class Dog : System.Object {

// Default constructor generated by compiler

public Dog() {

Base.Dog(); // Call to default constructor in System.Object

// All other code to be executed by Dog objects

} // end default constructor

} // end class Dog

As this example reveals, the compiler will generate the required constructor automatically along with a call to the base class's default constructor. But what about the situation in which the base class does not have an accessible default constructor? This can easily happen in any class in which the author writes one or more non-default constructors of his (or her) own. In such a case, the derived class definition will not compile if it contains a constructor that does not have an explicit call to a base class constructor at the beginning of its code. Note that the Object class contains a public default constructor. ***** Skip to End Skip 1 *****

The best practice you can adopt when writing constructors for derived classes is to ALWAYS write the call to a base class constructor for any constructor you write for a derived class.

Page 18: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 18

Sequence of Execution of Constructors Here we consider the sequence in which derived class constructors are executed during object instantiation. To understand how this works, we examine the scenario where you instantiate an object of the type Worker.

When you instantiate a Worker object, a constructor in the Worker class begins to execute (which constructor is selected depends upon the arguments you use when you instantiate the object).

This constructor must call a constructor in its base class (Employee, in this case). (This will happen if you write such an explicit call or if the compiler generates a call to the base class default constructor).

The constructor in the base class faces the same constraints. It must call the default constructor of its parent class (Person in our case).

The important observation is that constructors must execute in a chain starting with the least-derived (top-level) class (i.e., Object) and ending with the most-derived (bottom level) class. The implementation for the constructor of the Object class always runs to completion first. In the case of creating a new Worker object, when the constructor for the Object class completes, it returns and the constructor for the Person class and then to the Employee class, all of which must run to completion before the Worker constructor can run.

E.7 Polymorphism and Type Substitution (Replacement) Inheritance was presented as an effective way to reuse the implementation details of a base class (via construction of derived classes). Another aspect of inheritance lies in its support for polymorphic programming. Polymorphism Every derived class inherits the programming contract that is defined by the accessible members of its base class. As a result, you can program against any object created from a derived class by using the same programming contract (that is, the same method with the same argument list and return value) defined by the base class. In other words …

Inheritance provides the ability to program against different types of objects using a single programming contract. This is known as polymorphism (from the Greek meaning "having multiple forms").

Page 19: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 19

This polymorphic programming style is a powerful programming technique because it allows you to write generic code. To put it another way, the code, which is written against the base class, is also compatible with any of the derived classes, because they all share a common, inherited design. The derived classes are thus plug-compatible from the perspective of your code, making your code more applicable to a wider range of situations. (Look at some Project IV examples – save and display for example). Polymorphism can be envisioned as the notion that an operation (method) supports (may be used on) operands of one or more types (defined using classes). For example, you can write "X + Y", and the + operation will work in .NET whether X and Y are both integers, floats, decimals (etc.) or strings. Hence the operator "+" is polymorphic, and the code "X + Y" is an example of polymorphic programming. Example 7 (simple operator overloading):

a.) We could define a fraction class (using integer numerators and denominators) that

overloaded the operations +, -, *, /, as well as some basic I/O functions. Then if f1

and f2 were two instantiated objects of that class, the operation

f1 + f2

would make sense. (How would you write the code that carries out this operation using integer operators only?)

b.) The same argument could be made for a set class (How would you define the +

operation on sets?) c.) On the other hand, the + operator defined on a student class might make much

less sense and probably would not be defined for such a class. It also makes little sense when defined on the character data type. Try writing the code

a = ‘b’ + ‘c’;

in C# (with a of the character data type) and see what you get. Try it in C. It

actually works. Do you know why? You are already familiar with the idea of overloading as it has been used in many lan-guages. In fact, overloading has been used in higher level programming languages since the mid 1950s, long before the class concept was introduced. The use of overloaded operators in the case of the fraction class illustrates how overloaded operators can be extended using classes to define additional “versions” of the same operator.

Page 20: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 20

Static or Compile-Time Binding It is important to emphasize the role of the compiler in determining the type of operation (integer, float, fraction, etc) to be performed. In the next example, we examine another situation in which the compiler acts to decide which version of a method to select. These two examples (Examples 8 and 9) involve the use of static (compile-time) binding. But lurking in the wings is an even more interesting situation, dynamic, execution-time binding, where the determination of the method to be used is done during execution, based on the type of the object preceding the “.” in the call of the method. You have actually seen and probably implemented static method binding when writing multiple constructors for a class. [How did these constructors (all having the same name) differ from one another? And, how did the compiler determine which constructor to call in each case?] In Example 8, we examine a slightly different version of static method binding.

Example 8: Method overloading or static replacement adds yet another dimension to polymorphic programming. This is a bit more complicated, because the compiler now must examine the argument list used in the call in order to determine which version of the

method gets called. For example, in the following, the WriteLine method is overloaded: public static class Console {

public void WriteLine();

public void WriteLine(string value);

public void WriteLine(bool value);

...

}

Note carefully that all three of these methods are defined in the same class, a requirement when overloading is used. In this example, the C#.NET compiler will generate the call to the implementation of

WriteLine(string value)when it determines that the caller is passing a string

argument (such as "frank" or name). It will call the version of WriteLine (bool

value) when it sees a call such as WriteLine(flag); assuming the flag is a type

bool variable.

Note carefully that in this discussion of simple operator overloading (using the + operator in this case), we assume the existence of many different versions of the same operator, all having the same name (plus) and the same list of arguments. The compiler determines which operator to apply simply by examining the type of the operands involved in an operation.

Page 21: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 21

Polymorphism is a very powerful feature of object-oriented programming. It allows you to program in more generic terms and to substitute (replace) different compatible implementations for one another. To design, write, and use class definitions in C# .NET that benefit from polymorphism, however, you must understand a number of additional concepts. The first is the difference between an object type and a reference variable type. Example 9: (From the Employee-Manager Project) -- on overloadable methods in which

The argument list is used to determine which method is dispatched by a call

The argument list involves the use of references to objects that are instances of classes in a class hierarchy

This example is based on the class hierarchy shown in Figure E.4 (taken from your Final Project Employee-Manager example). Figure E.4 Product Hierarchy in the Employee-Manager Example.

As shown in Figure E.4 for the EmpMan Project, we have 5 classes. For the leaf node classes (Client, Manager, and Worker) we can create objects and reference those objects in the project. For the Person and Employee classes, we are not allowed to create

In all polymorphic cases (thus far), the COMPILER determines the version of the method that that is used by examining the operands or arguments used in the call and choosing the version of the method with matching operands. If there is no such version, the compiler will generate an error.

Employee-Manager Type Hierarchy (abbreviated version)

Person

Client Employee

Worker Manager

Page 22: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 22

objects, as they are declared to be abstract. This enables us to model all the entities in

our system without necessarily creating objects for each.

As the user of the EmpMan system creates objects of type Client, Manager, or Worker, these objects are added to a list of Persons. This addition of an object to the list of persons might be done as shown next. The list itself is created and hidden in

PersonList class using the declaration

private List <Person> HiddenPersonList = new List<Person> ();

The code to add an item (Client, Worker, or Manager object) to the list is also in the

PersonList class:

// Add a Person to the List public void Add(Person e) { HiddenPersonList.Add(e); } // end Add Worker, Client, or Manager Object to the PersonList

This add method can be called by any of the following three statements.

thisPersonList.Add(thisClient); thisPersonList.Add(thisManager); thisPersonList.Add(thisWorker);

Here we assume there is a declaration PersonList thisPersonList = new PersonList();

in the same class as the calls to Add.

The 3 types of objects (Client, Manager, and Worker. are

subtypes of the Person type, yet all of them may be added to the

List (of Person) declared above. Thus a list may contain objects of

different types as long as the types of these objects are subtypes of

the base type (Person in this case) of the list elements. This seems

simple enough, but as we shall see in Section E.8, it creates some

interesting problems if we want to process (for example, display)

elements of this list. More on this to come.

Page 23: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 23

E.8 Replacing Methods in a Derived Class

Dynamic Binding -- How members of a class are accessed at runtime Static and dynamic binding represent two different ways in which a client can invoke a method or property of an object. Static binding is usually more straightforward and results in better performance. With static binding, determinations of which version of a class member (such as a property or method) is called is done at compile time. We have already examined a number of examples of static binding, and we will look at one more here. For example, if I wish to save information about a Client, Manager, or Worker object, I can use calls to the corresponding version of the Save method contained in these classes: Client thisClient = new Client();

thisClient.Save(this);

or

Manager thisManager = new Manager();

thisManager.Save(this);

or

Worker thisWorker = new Worker();

thisWorker.Save(this);

Even though the argument lists in these calls are the same, there is no confusion for the compiler as to which version of the method Save is being called. This is completely determinable at compile time by the type of the object specified using the dot notation.

Now, however, suppose we to display the contents of an item in the Person list. private List <Person> HiddenPersonList = new List<Person> ();

We could write a method call such as HiddenPersonList[i].display();

However, recall that the items in the list can be of three different types, Client, Manager, or Worker. Since at least some of the attributes of these three data types are different,

each has its own display method. But, looking strictly at the syntax of the above call,

we have no way of knowing at compile time the type of the object to be displayed and

therefore, no way of determining which display method to call. This is where dynamic

binding comes into play.

Page 24: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 24

Dynamic binding yields greater flexibility and is the underlying mechanism that allows a derived class to replace behavior inherited from a base class at runtime. It is one of the crucial ingredients of polymorphic programming. Recall that with static binding the type of the reference variable (referencing an object) object that precedes a class member reference is used to decide at compile time which class member (method or property) is being accessed. For example: solutionObject.compare(guessAreaEntry[i]);

Here the reference variable is solutionObject and its type is known at compile time

(type SolutionClass, perhaps). But in the example just shown,

HiddenPersonList[i].display();

the type of the object being referenced by the reference variable is not known to the compiler, but can only be known at execution time when an object is actually stored in

HiddenPersonList[i]. Only then can the type of the referenced object be

determined.

We now look at another example involving the use of C# lists simply to reinforce what we have said to this point. In this example, as in the previous one, there is no way of determining at compile time the type of object being referenced by any entry of the list. All

list entries are defined as references to objects type of type Person. As such, however,

they can contain objects of type Person or any of the types derived from Person.

Example 10: The Person Class in the Empman Project contains its own version of the

tostring method. The Person version is illustrated below.

public override string ToString()

{

string s = "ObjectType : " + base.ToString() + "\n";

s += "PersonName : " + HiddenPersonName + "\n";

Static binding is the default access (invocation) mechanism used by C# .NET and by the CLR. It is based on the type of the reference variable, not the type of object being referenced used in the reference to a method. When dynamic binding is used (involving runtime replacements of class members and

the keywords override), the determination as to which method is called is made during

execution based up the type of the object involved in the access expression. With static binding, the compiler can perform more of the work. For this reason, static binding can provide a measurable performance advantage over dynamic binding.

Page 25: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 25

s += "PersonBirthDate: " +

HiddenPersonBirthDate.ToShortDateString() + "\n";

s += "PersonID :" + HiddenPersonID;

return s;

} // end ToString

This method builds a string by concatenating the name, birthdate, and ID of a Person.

This version overrides the base class (Object Class, in this case) version of ToString.

In addition, the subclasses of the Person class have their own versions of ToString

each of which are referenced as follows with a clause of the form x.ToString(). For

example, the version of ToString in the Worker class looks like this:

public override string ToString()

{

string s = base.ToString() + "\n";

s += "WorkerHourlyPay: " + HiddenWorkerHourlyPay.ToString();

return s;

} // end ToString

The existence of these ToString methods raises a number of issues. But the simple

fact that we want to illustrate here has to do with the determination of the version of

ToString that is called.

Question 1: Which version of ToString is called in the line

HiddenWorkerHourlyPay.ToString("C") ANSWER: The version that is called is determined wholly by the type of the object that

precedes the reference (HiddenWorkerHourlyPay in this case). This type is

determined by the compiler at compile time. We say that any such determination done at compile time is considered to be a static determination. To state this in another way: we

say that the version of ToString that is to be called is bound (determined) at compile

time. Question 2: Consider the following declaration: private List <Person> HiddenPersonList = new List<Person> (); In the reference HiddenPersonList[i].toString()

how does the compiler know which version to call?

Page 26: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 26

ANSWER: The compiler does NOT know which version of toString to call (access)

because the Person version of toString is defined so as to be overridden by a specific

product version (such as Manager or Employer) at runtime. In this case, the

determination as to which version of toString is to be accessed has to be made at

runtime, after the type of the object referenced by HiddenPersonList[i] has been

determined. Thus, if we assigned a Worker object to HiddenPersonList[i] then the

Worker class version of ToString would be called. But the assignment of objects to the

list is done at run time, so only at run time can we determine the type of the object store

in HiddenPersonList[i] . (If no object had yet been assigned at the time of this

reference, an exception would be raised.) Note that this approach to resolving references carries with it considerable "effort" for both the compiler and the runtime system (the CLR). All the type information involved has to be carried along at run time with the data stored in the list. The compiler has to provide all this information, and the CLR has to use it during execution in order to

determine the correct version of ToString to use in the above reference.

Question 3: Is the version of ToString in the Person Class ever used? Why or

why not? If not, why bother having it?

ANSWER: The Person version of ToString is used even though there are no

Persons per se but only products derived from the Person class.

However, there are numerous examples in which specific members of a base class have no work to do because all work is done by the overriding members of the derived class. In

such cases, the base class member is still required as an abstract member, but it has

no implementation: public abstract string findStudent ();

Class members marked as abstract include no implementation code of their own (and

they have no body either). It is also not possible to instantiate objects of an abstract

type. Any class that contains one or more abstract members should be marked with a

virtual keyword.

NOTE: If you want to go to extremes and write an abstract class with only definitions and no implementations, you can do this. Such a class is called an Interface in C# .NET)

The Person class might be suited to this idea in the EmpMan Project, because we do not

intend to ever instantiate any objects of type. Even so, there are some members of the Person class that have useful implementations to be inherited by derived classes, so we chose not to make the Person class an interface.

Note that all Interface members are automatically public so access modifiers are not needed. Interfaces can include functions, events, properties, other interfaces, classes,

Page 27: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 27

and structures. Interfaces can also inherit from other interfaces. Classes derived from an interface can pick and choose the members they implement – no one derived class has to implement all members of an Interface. There is lots more to be learned about interfaces, but we will not delve into this topic any further in this document. Dynamic Binding and Overridable Methods (review)

Recall that we claimed earlier in this chapter that one of the most valuable features of inheritance is the fact that the designer of a base class can provide default behavior that can optionally be replaced by a derived class author. Often, a base class author can provide a default implementation for a method. A derived class author can then choose whether to use the base class implementation or to write a more specialized implementation. In some cases, a derived class author even has the option of extending the base class implementation by adding extra code to the derived class. Using a derived class to replace the implementation of a method or a property defined in a base class is known as overriding. Method overriding relies on dynamic binding, not static binding. Overriding a method in a parent class requires that the parent method be

written with the modifier virtual(in C# (overridable in VB). You will note that both

the Save and Display methods in the Person class were written using this modifier so

that they could be overridden by the Save and Display methods in the subclasses of

the Person class.

Dynamic binding takes into account the type of an object at runtime, which gives the CLR a chance to locate and call the overriding method. In this way dynamic binding supports more flexible code, albeit with a runtime cost. Dynamic binding is the default in the Java programming language and, in fact, the only option in Java in most cases. It is sometimes useful to use a picture to help remember what a list such as

HiddenPersonList[i] really looks like. Figure E.5 on the next page illustrates what

this list might look like, although it is not an expertly drawn picture. Just for fun, we added two other types, a Student type (a derived type fro Person) and a Faculty type (a derived type from Employee). Try redrawing the picture in Figure E.1 with these two new types added.

It is important to note that this type of dynamically (runtime) determined dispatch requires the use of overridable methods with the same name and the same argument list.

Page 28: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 28

Figure E.6 HiddenPersonList – with 3 items of different types

Chaining Calls from a Derived Class to a Base Class (can be skipped)

When you override a method, it's fairly common practice to chain a call from your overriding implementation in the derived class to the overridden implementation in the base class. This technique allows you to leverage the implementation provided by the base class and extend it with extra code written in the derived class. Consider the following reimplementation of the Programmer class: public class Worker : Employee

{

. . .

public override void Save(frmEmpMan f)

{

base.Save(f);

HiddenWorkerHourlyPay =

Convert.ToDecimal(f.txtWorkerHourlyPay.Text);

} // end Save

. . .

[0]

[1]

[2]

[3]

[4]

[5]

Objet of

type

Worker

Object of

type

Manager

Object of

type

Faculty

Object of

type

Manager

Object

of type

Worker

Object of

type

Student

Object

of type Client

[6]

HiddenPersonList

Page 29: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 29

The C# .NET keyword base is used in a derived class to explicitly access public or

protected members in its base class. In this example, the Worker definition of Save

makes an explicit call to the Employee implementation of Save. This approach allows the

derived class author to reuse and extend the method implementation provided by the base class author. (Although not shown, note too that the Employee class version of

Save in turn references the Person version, extending our chain in this example to three

levels.) Note that chained calls do not have to be made at the beginning of the derived class implementation. They can be made at any point in the overriding implementation. Design Issues with Overridable Methods (can be skipped) Anyone who has managed a large software project using inheritance and method overriding can tell you that managing the semantics of overridable methods and properties requires a high level of expertise and attention to detail. An overridable method complicates the programming contract of a base class because a derived class author can use any of three possible approaches:

inherit a base class implementation and reuse it without modification.

provide an overriding implementation that chains a call back to the base class implementation (extends the original method).

provide an overriding implementation that does not chain a call back to the base class implementation (replacing the original method).

While the CLR's support for method overriding allows for reusing, extending, and replacing, many overridable methods have semantics that do not support all three approaches. We will not pursue these issues in this Lecture Set as it is a topic for a more advanced discussion on the method overriding in VB. Example 11: The game of Monopoly. Please click on the word Monopoly to see a full explanation of another example of the benefits of using inheritance with function overrides, chaining, etc.

E.9 Summary

As you read through this material, one theme probably became clear: The use of inheritance increases your responsibilities both during the design phase and during the coding phase. If you decide to create a class from which other classes will inherit, you must make several extra design decisions.

Page 30: CIS 3309 - Lecture Set E - Classes - Temple Universitycis-iis1.temple.edu/cis3309/Lecture Set ZZZ Appendix E... · CIS 3309 - Lecture Set E - Classes (Ver 15: November 13, ... The

Appendix E – Inheritance 11/14/2017 4:07:55 PM Page 30

If you make these decisions incorrectly, you can get yourself into hot water pretty quickly. This is especially true when you need to revise a base class after other programmers have already begun to use it. The first question you should address is whether it makes sense to use inheritance in your designs. In other words, should you be designing and writing your own base classes to be inherited by other classes? Once you've made a decision to use inheritance in this manner, you take on all the responsibilities of a base class author. It's your job to make sure that every derived class author understands the programming contract your base class has defined for its derived classes. While you may never create your own base class, you will more than likely create custom classes that inherit from someone else's base class. It's difficult to imagine that you could program against the classes of the FCL without being required to inherit from a system-provided base class such as the Form class, the Page class, or the WebService class. Because so many of the class libraries in the .NET Framework have designs that involve base classes, every .NET developer needs to understand the responsibilities of a derived class author. If you don't have a solid understanding of the issues at hand, you will find it difficult to implement a derived class correctly.