Embed
Email

Inheritance

Document Sample

Shared by: linzhengnd
Categories
Tags
Stats
views:
3
posted:
11/8/2011
language:
Estonian
pages:
44
Read Chap. 12



9. OOP & ADTs: Introduction to Inheritance

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

A major objective of OOP: writing reusable code

(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:

 Inheritance: Define one class (derived class) in terms of



another (base) class, reusing the data members and function

members of the base class. 1

Example: Suppose a problem requires stack operations not provided

in our stack class — e.g., max(), min()



Ways to Approach this:

#1: Add function members to the Stack class that implement the

new operations.



Stack class

new operations

push(), pop(), ...

myTop, ...

new data members





Bad: This can easily mess up a tested, operational class,

creating problems for other client programs.

2

#2: An adapter approach: Build a new RevStack class that

contains a Stack as a data member.



RevStack

class

new operations

including revised

push(), pop(), ...



Stack stObj

push(), pop(), ...



myTop, ...

new data members





Better, but:

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



3

#3: Copy-&-paste approach: Build a new RevStack class,

copying and pasting the data members and function

members of Stack into RevStack .



Stack class RevStack

push(), pop(), ... class

new operations

myTop, ... push(), pop(), ...

myTop, ...

new data members







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. 4

#4: Object-oriented approach:

Derive a new class RevStack from the Stack class,

which is called its parent class or base class.



This is the best:

(i) A derived class inherits all members of its parent 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.









5

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

follows:

1. Identify the objects in the problem

2. Look for commonality in those objects

3. Define base classes containing that commonality

4. Define derived classes that inherit from the base class

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



Object-oriented programming (OOP) was first used to describe the

programming environment for Smalltalk, the earliest true object-

OOP languages have three

oriented programming language. done this

We've

important properties:

 Inheritance

 Polymorphism, with the related concept of

Encapsulation

dynamic or late binding





6

B. Derived Classes

Problem: Model various kinds of licenses.

Old Approach: Build separate classes for each license from scratch

OOD: 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

...

};

7

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 HuntingLicense

class DriversLicense

{ {

public: public:

... ...

private: private:

License common; License common;

int myVehicleType; string thePrey;

string myRestrictionsCode; Date seasonBegin,

... seasonEnd;

}; ...

};

class PetLicense

{

public: This has-a relation (inclusion)

...

private:

defines containment; i.e., when one

License common; object contains an instance of

string myAnimalType; another object.

...

};



8

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 is-a relationship because

a driver’s license is a license

9

So we need: a DriversLicense is a License,

not a DriversLicense has a License.

 we need inheritance.



We will derive the specialized license classes

from the base class License and

add new members to store and operate on

their new attributes.



Problem:

Private class members cannot be accessed outside of

their class (except by friend functions), not even

within derived classes.



10

One C++ solution:

Members declared to be protected: 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

protected section:class License

{

public:

// Function members

// Display(), Read(), ...

protected:

long myNumber;

string myLastName,

myFirstName;

char myMiddleInitial;

int myAge;

Date myBirthDay;

...

}; 11

Now we can derive classes for the more specialized licenses from

License:

class DriversLicense : public License

{

public:

...

protected:

int myVehicleType;

string myRestrictionsCode;

...

};

class HuntingLicense : public License

{

public:

...

protected:

string thePrey; class PetLicense : public License

Date seasonBegin, {

seasonEnd; public:

... ...

}; protected:

string myAnimalType;

...

};



12

Classes like DriversLicense, HuntingLicense, and

PetLicense are said to be derived classes (or child classes or

subclasses),

and the class License from which they are derived is called a base

class (or parent class or superclass).

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 HuntingLicense

{

public:

...

protected:

int theAntlerMaximum;

int theBullwinkleFactor;

...

};



13

This leads to class hierarchies — usually pictured as a tree

but with arrows drawn from a derived class to its base class:



License







Drivers Hunting ... Pet

Licens e Licens e Licens e



... ... ...



Car Unicycle Moose Dinosaur Dog Hamster

Licens e Licens e Licens e Licens e Licens e Licens e





Each non-root class inherits the members of its ancestor

classes.

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. Java API 14

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.)



15

The Fundamental Property of Derived Classes

They inherit the members of the base class

(and thus the members of all ancestor 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  private

protected  protected





16

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 is-a relationship:

For class Derived : public Base

{

// ... members of Derived ...

};

every Derived object is a Base object.



For example: A HuntingLicense is a License

A MooseLicense is a HuntingLicense

A MooseLicense is a License

17

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.

18

A third relationship between classes is the uses

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?

19

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:



Attributes Attributes

Common Common

to Object 1 to Object j

thru Object i thru Object n

...

... ...

Object 1 Object i Object j Object n



20

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





Attributes Common

to Object 1 thru Object n







Attributes Attributes

Common ... Common

to Object 1 to Object j

thru Object i thru Object n





21

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):

Attributes Common

to Object 1 thru Object n







Attributes Attributes

Common ... Common

to Object 1 to Object j

thru Object i thru Object n 22

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

system are built:

Attributes Common

to Obje ct 1 thru Object n







Attributes Attributes

Common ... Common

to Object 1 to Object j

thru Object i thru Object n



... ...

Object 1 Object i Object j Object n



7. These classes can then be used to construct the

system’s objects. 23

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 employees

Hourly employees

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

share?

Id number

Name

Department

...



24

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



class Employee

{

public:

// ... various Employee operations ...



protected:

long myIdNum; // Employee's id number

string myLastName, // " last name

myFirstName; // " first name

char myMiddleInitial; // " middle initial

int myDeptCode; // " department code



// ... other members common to all Employees

};









25

4. From the base class, derive classes containing special

attributes: employee class:

a. A salaried

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;

26

};

and others . . .





Employee









Salaried Hourly Commissione Contract

Employee Employee d Employee

Employee









Pro- Consul- Secre- Tech

Manager Support Sales Reviewer Editor

grammer tant tary









Execu- Super-

tive visor



27

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 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.

40

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 = 0 to the

function's prototype:

virtual PrototypeOfFunction = 0;

No definition of the function is given in the base class.

Classes derived from it must provide a definition.

41

E.Hetergeneous Data Structures

Consider a LinkedList of Employee objects:

LinkedList 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:



L

n emp1 emp2 emp_n

...





Such a list is a homogeneous structure: Each value

in the list must be of the same type (Employee).

42

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: HourlyEmployee



Employee SalariedEmployee



L

n emp1 emp2 emp_n







...





Thus, salaried and hourly employees can be intermixed in

the same list, and we have a heterogeneous storage

43

structure.

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. 44



Related docs
Other docs by linzhengnd
option strategy excel spreadsheet
Views: 3  |  Downloads: 0
Tips on Effective Listening
Views: 0  |  Downloads: 0
TO DOWNLOAD TEXT - Repairing The Breach
Views: 0  |  Downloads: 0
Power-Up Tested - Access Mobile
Views: 4  |  Downloads: 0
6502 Sell stone monuments and memorials
Views: 0  |  Downloads: 0
Sheet1 - Atlanta International School
Views: 2  |  Downloads: 0
AFRICAN UNION
Views: 0  |  Downloads: 0
By registering with docstoc.com you agree to our
privacy policy

You are almost ready to download!

You are almost ready to download!