+ All Categories
Home > Documents > 9. OOP & ADTs: Introduction to Inheritance

9. OOP & ADTs: Introduction to Inheritance

Date post: 14-Jan-2016
Category:
Upload: thea
View: 41 times
Download: 0 times
Share this document with a friend
Description:
Read Chap. 12. 9. OOP & ADTs: Introduction to Inheritance. A. Inheritance, OOD, and OOP (§12.1 & 12.2) A major objective of OOP: ______________________________ (to avoid re-inventing the wheel). Ways to do this in C++: Encapsulate code within functions Build classes - PowerPoint PPT Presentation
Popular Tags:
44
1 9. OOP & ADTs: Introduction to Inheritance Read Chap. 12 A. Inheritance, OOD, and OOP (§12.1 & 12.2) A major objective of OOP: ______________________________ (to avoid re-inventing the wheel). Ways to do this in C++: Encapsulate code within functions Build classes Store classes and functions in separately-compiled libraries Convert functions into type-parameterized function templates Convert classes into type-parameterized class templates. An additional approach that distinguishes OOP from the others:
Transcript
Page 1: 9.  OOP & ADTs:  Introduction to Inheritance

1

9. OOP & ADTs: Introduction to Inheritance

Read Chap. 12

A. Inheritance, OOD, and OOP (§12.1 & 12.2)

A major objective of OOP: ______________________________(to avoid re-inventing the wheel).

Ways to do this in C++: Encapsulate code within functions Build classes Store classes and functions in separately-compiled

libraries Convert functions into type-parameterized function

templates Convert classes into type-parameterized class

templates.

An additional approach that distinguishes OOP from the others:

_______________: Define one class (derived class) in terms of another (base) class, reusing the data members and function members of the base class.

Page 2: 9.  OOP & ADTs:  Introduction to Inheritance

2

Example: Suppose a problem requires stack operations not provided in our stack class

Ways to Approach this: #1: Add function members to the Stack class that

implement the new operations.

Bad: This can easily mess up a tested, operational class, creating problems for other client programs.

new operations

push(), pop(), ...

myTop, ...

new data members

Stack class

Page 3: 9.  OOP & ADTs:  Introduction to Inheritance

3

#2: An adapter approach: Build a new RevStack class that contains a Stack as a data member.

Better, but:

A RevStack is not a Stack; it has a Stack.

new operations including revised push(), pop(), ...

new data members

RevStack class

push(), pop(), ...

myTop, ...

Stack stObj

Page 4: 9.  OOP & ADTs:  Introduction to Inheritance

4

#3: Copy-&-paste approach: Build a new RevStack class, copying and pasting the data members and function members of Stack into RevStack .

Almost right, but:

These are separate independent classes. Modifying Stack (e.g., changing from an array to a linked list for the stack elements) doesn't automatically update a RevStack.

new operations

new data members

RevStack class

push(), pop(), ...

myTop, ...

push(), pop(), ...

myTop, ...

Stack class

Page 5: 9.  OOP & ADTs:  Introduction to Inheritance

5

#4: Object-oriented approach: ____________________________________________________ , which is called its ______________ or ______________.

This is the best:

(i) A derived class ______________________________________ (including its operations); we need not reinvent the wheel.

(ii) Modifying the Stack class automatically updates the RevStack class.

(iii) Mistakes made in building RevStack class will be local to it;

the original Stack class remains unchanged and client programs

are not affected.

Page 6: 9.  OOP & ADTs:  Introduction to Inheritance

6

Object-oriented design (OOD) is to engineer one’s software as follows:

1. Identify the objects in the problem2. Look for ______________in those objects3. Define ______________________________________________4. Define ______________________________________________

These last two steps are the most difficult aspects of OOD.

Object-oriented programming (OOP) was first used to describe the programming environment for _____________, the earliest true object-oriented programming language. OOP languages have three important properties:

______________ ______________ ______________, with the related concept of

____________________________

Page 7: 9.  OOP & ADTs:  Introduction to Inheritance

7

B. Derived Classes

Problem: Model various kinds of licenses.Old Approach: Build separate classes for each license from scratchOOD: What attributes do all licenses have in common? Then store these common attributes in a general (base) class License:

class License{ public:

// Function members Display(), Read(), ...

private: // we'll change this in a minute long myNumber; string myLastName, myFirstName; char myMiddleInitial; int myAge; Date myBirthDay; // Date is a user-defined type

...};

Page 8: 9.  OOP & ADTs:  Introduction to Inheritance

8

We could include a data member of type License in each of the classes for the various kinds of licenses and then add new members:class DriversLicense{public:

... private:License common;int myVehicleType;string myRestrictionsCode;

...};

class HuntingLicense{public:

... private:License common;string thePrey;Date seasonBegin, seasonEnd;

...};

class PetLicense{public:

... private:License common;string myAnimalType;

...};

This has-a relation (inclusion) defines containment; i.e., when one object contains an instance of another object.

Page 9: 9.  OOP & ADTs:  Introduction to Inheritance

9

This inclusion technique works but it is a bit "clunky" and inefficient; for example, we need to "double dot" to access members of the included object:

DriversLicense h; ...h.common.Display(cout);

Worse... Can one say that a driver’s license is a license?

No! This is bad OOD.

Design should reflect reality not implementation.

What we really want is the ________ relationship because a driver’s license is a license

Page 10: 9.  OOP & ADTs:  Introduction to Inheritance

10

So we need: a DriversLicense is a License,

not a DriversLicense has a License.

we need __________________.

We will _____________the specialized license classes

from the __________________License and ______________________________________________________their new attributes.

Problem:

Private class members cannot be accessed outside of their class (except by friend functions), not even within derived classes.

Page 11: 9.  OOP & ADTs:  Introduction to Inheritance

11

class License{public: // Function members// Display(), Read(), ...

______________long myNumber;string myLastName, myFirstName;char myMiddleInitial;int myAge;

Date myBirthDay;...

};

C++ solution:

Members declared to be _______________ can be accessed within a derived class, but remain inaccessible to programs or non-derived classes that use the class (except for friend functions).

So change the private section in class License to a _______________________:

Page 12: 9.  OOP & ADTs:  Introduction to Inheritance

12

Now we can derive classes for the more specialized licenses from License:

class DriversLicense__________________{public:

... protected:int myVehicleType;string myRestrictionsCode;...

};class HuntingLicense_________________{public:

... protected:string thePrey;Date seasonBegin, seasonEnd;...

};

class PetLicense________________{public: ...

protected:string myAnimalType;

...};

Page 13: 9.  OOP & ADTs:  Introduction to Inheritance

13

Classes like DriversLicense, HuntingLicense, and PetLicense are said to be __________________(or _____________), and the class License from which they are derived is called a ______________or __________________ or __________________).

We have used protected sections rather than private ones in these derived classes to make it possible to derive "second-level" classes from these if/when it becomes necessary; for example:class MooseLicense__________________________

{public:

... protected:

int theAntlerMaximum;int theBullwinkleFactor;...

};

Page 14: 9.  OOP & ADTs:  Introduction to Inheritance

14

This leads to ________________________— usually pictured as a tree but with arrows drawn from a derived class to its base class: License

Drivers License

. . .

. . .. . .

Hunting License

Pet License

. . .

Car License

Unicycle License

Moose License

Dinosaur License

Dog License

Hamster License

Each non-root class ___________________________________________.

This means that an attribute needs to be defined only once (at the appropriate level), allowing a programmer to reuse the (one) definition many times.

Page 15: 9.  OOP & ADTs:  Introduction to Inheritance

15

Usual Form of Declaration of a Derived Class

DerivedClassName : public BaseClassName{ ...

// new data members and // functions for derived class

...}

(More generally, the keyword public can be replaced by private or protected.)

Page 16: 9.  OOP & ADTs:  Introduction to Inheritance

16

The Fundamental Property of Derived Classes

Other Properties:

They cannot access private members of the base class.

Access to public and protected members of the base class depends on the kind of inheritance specified in the heading:

public public and protected, respectively

private privateprotected protected

Page 17: 9.  OOP & ADTs:  Introduction to Inheritance

17

The most common is public inheritance; this is the only kind we will use. It means that:

We can use the public and protected members of the base class in a derived class just as though they were declared in the derived class itself.

It gives rise to the relationship:

For class Derived : public Base{

// ... members of Derived ...};

______________________________________________

For example: A HuntingLicense is a LicenseA MooseLicense is a HuntingLicense A MooseLicense is a License

Page 18: 9.  OOP & ADTs:  Introduction to Inheritance

18

The property that derived classes inherit the members of ancestor classes can easily be misused. For example, it is bad design to do the following just to get the members of one class into another:

class BusDriver : public License{ ... }

Rather, we should use:

class BusDriver{

...private: License myLicense;// a bus driver has a license...

};Design Principle: Don't use public inheritance for the has-a relationship.

Page 19: 9.  OOP & ADTs:  Introduction to Inheritance

19

A third relationship between classes is the relationship: One class might simply use another class. For example, a Fee() member function in a LicensePlate class might have a parameter of type DriversLicense. But this class simply uses the DriversLicense class — it is not a DriversLicense and it does not have a DriversLicense.

It isn't always easy to tell which is the appropriate one to use. Two useful tests in deciding whether to derive Y from X:

1. Do the operations in X behave properly in Y?

2. (The "need-a use-a" test): If all you need is a Y,

can you use an X?

Page 20: 9.  OOP & ADTs:  Introduction to Inheritance

20

Summary:

The OOP approach to system design is to:

1. Carefully analyze the objects in a problem from the bottom up.

2. Where commonality exists between objects, group the common

attributes into a base class:

Object 1 Object i

AttributesCommonto Object 1

thru Object i

. . .

Object j Object n

AttributesCommonto Object j

thru Object n

. . .

. . .

Page 21: 9.  OOP & ADTs:  Introduction to Inheritance

21

3. Then repeat this approach “upwards” as appropriate:

AttributesCommonto Object 1

thru Object i

AttributesCommonto Object j

thru Object n

Attributes Common to Object 1 thru Object n

. . .

Page 22: 9.  OOP & ADTs:  Introduction to Inheritance

22

Once no more commonality exists, OO implementation then:

4. Proceeds from the top down, building the most general base class(es): Attributes Common

to Object 1 thru Object n

5. The less-general classes are then derived (publicly) from that

base class(es):

AttributesCommonto Object 1

thru Object i

AttributesCommonto Object j

thru Object n

Attributes Common to Object 1 thru Object n

. . .

Page 23: 9.  OOP & ADTs:  Introduction to Inheritance

23

6. Derivations continue until classes for the actual objects in the

system are built:

7. These classes can then be used to construct the

system’s objects.

AttributesCommonto Object 1

thru Object i

AttributesCommonto Object j

thru Object n

Attributes Common to Object 1 thru Object n

Object 1 Object i

. . .

Object j Object n

. . .

. . .

Page 24: 9.  OOP & ADTs:  Introduction to Inheritance

24

C. Another (Classic) Example: Employees

Problem: Design a payroll system.

Following the four OOD steps, we proceed as follows:

1. Identify the objects in the problem:

Salaried employeesHourly employees

2. Look for commonality in those objects: what attributes do they share?

Id numberNameDepartment . . .

Page 25: 9.  OOP & ADTs:  Introduction to Inheritance

25

3. Define a base class containing the common data members:

class Employee{public:

// ... various Employee operations ...

protected:long myIdNum; // Employee's id numberstring myLastName, // " last name myFirstName; // " first namechar myMiddleInitial; // " middle initialint myDeptCode; // " department code

// ... other members common to all Employees};

Page 26: 9.  OOP & ADTs:  Introduction to Inheritance

26

4. From the base class, derive classes containing special attributes:a. A salaried employee

class:class SalariedEmployee : public Employee{public:

// ... salaried employee operations ...

protected:double mySalary;

};

b. An hourly employee class:class HourlyEmployee : public Employee{public:

// ... hourly employee operations ...

protected:double myWeeklyWage, myHoursWorked, myOverTimeFactor;

};

Page 27: 9.  OOP & ADTs:  Introduction to Inheritance

27

and others . . .

Employee

Commissioned

Employee

ContractEmployee

SalariedEmployee

HourlyEmployee

Manager Pro-grammer Sales Reviewer Editor

Execu-tive

Super-visor

Consul-tant

Secre-tary

TechSupport

Page 28: 9.  OOP & ADTs:  Introduction to Inheritance

28

All of the classes that have Employee as an ancestor inherit the members (data and function) of Employee.

For example, each HourlyEmployee and Manager object is an Employee object so each contains the members myIdNum, myLastName, myFirstName, and so on...

So, if Employee has a public operation to extract myIdNum,

long IdNumber() const { return myIdNum; }

then it can be used by hourly employees and managers:

HourlyEmployee hourlyEmp;Manager managerEmp; ...cout << hourlyEmp.IdNumber() << endl << managerEmp.IdNumber() << endl;

Page 29: 9.  OOP & ADTs:  Introduction to Inheritance

29

Reusability:Suppose we define an output function member in Employee:

void Employee::Print(ostream & out) const{ out << myIdNum << ' ' << myLastName << ", " << myFirstName << ' ' << myMiddleInitial << " " << myDeptCode << endl;}

In derived classes, we can override Print() with new definitions that reuse the Print() function of class Employee.A class Deriv derived from class Base

can call Base::F()

to reuse the work of the member function F() from the base class.

Page 30: 9.  OOP & ADTs:  Introduction to Inheritance

30

void HourlyEmployee::Print(ostream & out) const{ ______________________________ ; //inherited members out << "$" << myWeeklyWage << endl //local members << myHoursWorked << endl << myOverTimeFactor << endl;}

For example:

void SalariedEmployee::Print(ostream & out) const{ _____________________________ ; //inherited members out << "$" << mySalary << endl; //local members}

Page 31: 9.  OOP & ADTs:  Introduction to Inheritance

31

Is-a and Has-a Relationships:

An object can participate in is-a and has-a relationships simultaneously.

For example, we could define an address class

class Address{

public: string street, city, state, zip; }

and use it to declare some data member in the class Employee.Then, for example, a SalariedEmployee is-an Employee

and has-an Address.

Page 32: 9.  OOP & ADTs:  Introduction to Inheritance

32

Constructors and Inheritance

Consider Employee's constructor// Explicit-Value Constructorinline Employee::Employee(long id, string last, string first, char initial, int dept){ myIdNum = id; myLastName = last; myFirstName = first; myMiddleInitial = initial; myDeptCode = dept;}

A derived class can use a member-initialization-list

to call the base-class constructor to initialize the inherited data members — easier than writing it from scratch.

Page 33: 9.  OOP & ADTs:  Introduction to Inheritance

33

// Definition of SalariedEmployee explicit-value constructorinline SalariedEmployee::SalariedEmployee (long id, string last, string first, char initial, int dept, double sal)

______________________________________________________

From the derived class constructor, pass the id number, last name, first name, middle initial and dept. code to the Employee constructor to initialize those members.

{ _________________________}

SalariedEmployee()then initializes only its own (local) member(s).

Page 34: 9.  OOP & ADTs:  Introduction to Inheritance

34

General form of Member-Initialization-List Mechanism:

Derive::Derive(ParameterList) : Base(ArgList){ // initialize the non-inherited members // in the usual manner ...}

Initializations in a member-initialization-list are done first, before those in the body of the constructor function.

General Principle of Derived Class Initialization

Use the base class constructor to initialize base class members, and use the derived class constructor to initialize derived class members.

Page 35: 9.  OOP & ADTs:  Introduction to Inheritance

35

Member-initialization list can also be used to initialize local data members in the derived class:

Data member datamem of a derived class can be initialized to

an initial value initval using the unusual function notation

datamem(initval) in the member-initialization list.

Example:inline SalariedEmployee::SalariedEmployee (long id, string last, string first, char initial, int dept, double sal)

: Employee(id, last, first, initial, dept){}This is less commonly used than "normal" initialization datamem = initval; in the function body. It is used when initialization is desired before the constructor fires.

___________________

Page 36: 9.  OOP & ADTs:  Introduction to Inheritance

36

D. Polymorphism

Consider:class Employee{public: Employee(long id = 0, string last = "", string first = "", char initial = ' ', int dept = 0);

void Print(ostream & out) const;

// ... other Employee operations ...

protected: // ... data members common to all Employees};

// Definition of Printvoid Employee::Print(ostream & out) const{ . . . }

// Definition of output operator<<ostream & operator<<(ostream & out, const Employee & emp){ emp.Print(out); return out; }

Page 37: 9.  OOP & ADTs:  Introduction to Inheritance

37

And suppose we have overridden Print() for the subclasses SalariedEmployee and HourlyEmployee as described earlier.

The statements:Employee emp(11111, "Doe", "John", 'J', 11);SalariedEmployee empSal(22222, "Smith", "Mary", 'M', 22,

59900);HourlyEmployee empHr(33333, "Jones", "Jay", 'J', 33, 15.25,

40);

cout << emp << endl << empSal << endl << empHr << endl;

then produce as output:not:11111 Doe, John J 11

22222 Smith, Mary M 22$59900

33333 Jones, Jay J 33$15.25401.5

11111 Doe, John J 11

22222 Smith, Mary M 22

33333 Jones, Jay J 33

Page 38: 9.  OOP & ADTs:  Introduction to Inheritance

38

This is because the call to Print() in the definition of operator<<() uses Employee's Print(). What we need is ____________ or ____________: Don't ______________________ of a function member

to ________________to that function ______________________.

This is accomplished by declaring Print() to be a _________________ by prepending the keyword ____________ to its prototype in the Employee class:

class Employee{public: // ...

____________ void Print(ostream & out) const;

// ... other Employee operations ...

private: // ... data members common to all Employees};

Page 39: 9.  OOP & ADTs:  Introduction to Inheritance

39

This works; operator<<() will use

Employee::Print() for EmployeesSalariedEmployee::Print() for SalariedEmployeesHourlyEmployee::Print() for HourlyEmployees

The same function call can cause different effects at different times— has many forms — based on the function to which the call is bound.Such calls are described as _______________(Greek for "many forms").

Polymorphism is another important advantage of inheritance in OOP languages.

Thanks to polymorphism, we can apply operator<<() to derived class objects without explicitly overloading it for those objects. Note: This is a good reason to define operator<<() so

that it calls some output function member of a class rather than making it a friend function.

Page 40: 9.  OOP & ADTs:  Introduction to Inheritance

40

Another Example:

A base-class pointer can point to any derived class object.So consider a declaration

Employee * eptr;Since a SalariedEmployee is-an Employee, eptr can point to a SalariedEmployee object:

eptr = new SalariedEmployee; Similarly, it can point to an HourlyEmployee object:

eptr = new HourlyEmployee; For the call

eptr.Print(cout);to work, SalariedEmployee::Print(cout) must be used when eptr points to a SalariedEmployee, but HourlyEmployee::Print(cout) must be used when eptr points to HourlyEmployee.

Here is another instance where Print() must be a virtual function so that this function call can be bound to different function definitions at different times.

Page 41: 9.  OOP & ADTs:  Introduction to Inheritance

41

By declaring a base-class function member to be virtual, a derived class can override that function so that calls to it though a pointer or reference will be bound (at run-time) to the appropriate definition.

If we want to force derived classes to provide definitions of some virtual function, we make it a pure virtual function — also called an abstract function — and the class is called an abstract class .

This is accomplished in C++ by attaching __________ to the function's prototype:

____________ PrototypeOfFunction __________;

No definition of the function is given in the base class. Classes derived from it must provide a definition.

Page 42: 9.  OOP & ADTs:  Introduction to Inheritance

42

E.Hetergeneous Data Structures

Consider a LinkedList of Employee objects:

LinkedList<Employee> L;

Each node of L will only have space for an Employee, with no space for the additional data of an hourly or salaried employee:

Such a list is a homogeneous structure: Each value in the list must be of the same type (Employee).

...

n

L

emp1 emp2 emp_n

Page 43: 9.  OOP & ADTs:  Introduction to Inheritance

43

Now suppose we make L a LinkedList of Employee pointers:

LinkedList<_____________________> L;

Then each node of L can store a pointer to any object derived from class Employee:

Thus, salaried and hourly employees can be intermixed in the same list, and we have a heterogeneous storage structure.

...

n

Lemp1 emp2 emp_n

Page 44: 9.  OOP & ADTs:  Introduction to Inheritance

44

Now consider:

Node * nPtr = L.first;

while (nPtr != 0){nptr->data->Print(cout);nptr = nPtr->next;

}For the call

nPtr->data->Print(cout);

to work when nPtr->data points to a SalariedEmployee object,

SalariedEmployee::Print() within that object must be called;

but when nPtr->data is a pointer to an HourlyEmployee,

HourlyEmployee::Print() within that object must be called.

Here is another instance where Print() must be a virtual function.


Recommended