OOD and Inheritance (Chapter 5 in text). Designing With Inheritance Inheritance: the ability to...

42
OOD and Inheritance (Chapter 5 in text)

Transcript of OOD and Inheritance (Chapter 5 in text). Designing With Inheritance Inheritance: the ability to...

OOD and Inheritance

(Chapter 5 in text)

Designing With Inheritance

Inheritance: the ability to define new classes as refinements or extensions of previous ones

Inheritance is a central feature of OOD and OOP because:

1. Simplifies programming

2. Allows code to be reused through sharing

3. Can refine and extend code through virtual methods.

Example: Stacks and Queues

Front Rear

Items enterhere

Items exithere

Top

Items both enter and exit here

Stack as a Variation of Queue

Front Rear

Items enterhere

Items exithere

Front

Items enterhere

Items exithere

New Terminology

Conceived this way, stacks and queues differ only in where items enter

So we will call an ordinary queue a rear queue since items enter at rear First-in, First-out (FIFO)

We will call a stack a front queue since items enter front Last-in, First-out (LIFO)

Generalization Class Diagram

We will say that front queues and rear queuesare extensions (derived subclasses) of a general queue class:

Queue

FrontQueue RearQueue

Attributes (Data) in Common

What attributes do stacks (front queues) and queues (rear queues) have in common? An underlying structure (for example, an array) A place where items are added (for example, an

index) A place from which items are removed

Operations in Common

What operations do stacks and queues have in common (regardless of how the operations are implemented)? Create Add an item Remove an item Check for emptiness Check for fullness Display

Generalization Diagram Again

Queue

maxSize: Integerfront: Integerrear: Integer

display(): voidadd(Item): voidremove(): Itemempty(): Booleanfull(): Boolean

FrontQueue RearQueue

Item

*items

1

Abstract Classes

The Queue class is conceived to be what is common to both the FrontQueue and RearQueue classes

It makes no sense to make an object of type Queue; it is abstract (name in italics)

Operations in italics are abstract, like place holders; they must be overridden by the extending classes FrontQueue and RearQueue

The FrontQueue and RearQueue classes inherit data attributes from Queue

PolymorphismPolymorphism is the ability of a language to determinewhich operation to use among many of the same name.

Simple examples performed statically at compile time: - type conversion - operator overloading - function overloading by parameter and return types

Pure polymorphism is the ability to choose amongoperations of the same name dynamically at run time.

In C++, pure polymorphism is achieved throughinheritance and virtual functions.

An Abstract QueueInfo Class in C++

class QueueInfo {protected: ItemArray items; Integer maxSize; Integer front; Integer rear; public: QueueInfo(Integer size); ~QueueInfo(); void add(ItemArray newItems, Integer numItems); virtual void display(); virtual void add(Item item) =0 ; virtual Item remove() =0 ; virtual Boolean empty() =0 ; virtual Boolean full() =0 ; };

Notes on the QueueInfo Class

The protected keyword has the same meaning as private, except that protected data is accessible to class extensions (subclasses)

The virtual keyword on a method without the =0 body means the method may be overridden by subclasses

The virtual keyword on a method with the =0 body means the method must be overridden by subclasses (pure virtual method)

Notes on the QueueInfo Class (cont'd)

The QueueInfo constructor is not virtual, and will be shared by RearQueueInfo and FrontQueueInfo objects

Must be implemented by QueueInfo class

The add method is overloaded: The non-virtual version will be shared and must be

implemented by QueueInfo class The virtual version must have separate definitions in

both RearQueueInfo and FrontQueueInfo classes

The Difference Between Overloading and Overriding

Suppose q is of type FrontQueue. Consider: q->add(itemArray, numItems); q->add(item);

The difference between these two calls can be determined by the compiler on the basis of the calls' signatures

This is an example of method overloading Also called ad-hoc polymorphism

The Difference Between Overloading and Overriding (cont'd)

Suppose q is of declared type Queue. Consider: q->add(item);

Since the one-parameter add method is only defined for FrontQueues and RearQueues, which method does this refer to?

Answer: can only be determined at run-time by looking at the specific type for q

This is an example of method overriding Also called pure polymorphism

Pure Polymorphism Example

class CommandInterpreterInfo {private: Queue q; // either a RearQueue or FrontQueue Character cmd; // queue command: c, a, r, or d Character qtype; // queue type: r or f Integer qsize; // queue size . . .public: CommandInterpreterInfo(); void execute(); // run this command interpreterprivate: . . . void processCreate(); // process a cr or cf command void checkEOF(); // check for premature EOF . . .};

Pure Polymorphism Example (cont'd)

void CommandInterpreterInfo::processCreate() { if (cmd != 'c') { <error: first command must be create> } cin >> qtype; checkEOF(); if ( (qtype == 'f') || (qtype == 'r') || (qtype == 'p') ) { cin >> qsize; checkEOF(); switch ( qtype ) { case 'f': q = new FrontQueueInfo(qsize); cout << "Front"; break; case 'r': q = new RearQueueInfo(qsize+1); cout << "Rear"; break; case 'p': . . . } cout << " Queue Created of Size " << qsize << endl; } else { <error: bad queue type> }}

QueueInfo Constructor QueueInfo objects are not explicitly

constructed using new However, a QueueInfo constructor can be

defined as what is common between FrontQueueInfo and RearQueueInfo:

QueueInfo::QueueInfo(Integer size) { maxSize = size; items = new Item[maxSize]; for (Integer i = 0; i < maxSize; i++) { items[i] = NULL; }}

Defining Subclasses in C++:Example

class FrontQueueInfo : public QueueInfo {public: FrontQueueInfo(Integer n); void add(Item item); Item remove(); Boolean empty(); Boolean full(); void display();};

Similarly for RearQueueInfo

Notes on the Example

The ``: public QueueInfo'' construction means that FrontQueueInfo is to inherit all public and protected methods from QueueInfo

FrontQueueInfo has its own constructor to supplement that ``inherited'' from QueueInfo

FrontQueueInfo has a display method, even though it doesn't have to

Subclass Constructors

Constructors for subclasses indicate in their headerswhich parent class constructor to use:

FrontQueueInfo::FrontQueueInfo(Integer n): QueueInfo(n) { < code to initialize a new front queue >}

RearQueueInfo::RearQueueInfo(Integer n): QueueInfo(n) { < code to initialize a new rear queue >}

Non-Pure Virtual Methods

The display method in the QueueInfo class is virtual, but not pure

Thus, it has a definition in the QueueInfo class:

void QueueInfo::display() { for (Integer i = 0; i < maxSize; i++) { if ( items[i] == NULL ) cout << " ___" ; else items[i]->display(); } cout << endl;}

Non-Pure Virtual Methods (cont'd)

If a subclass does not override a nonpure virtual method, then its parent's definition will be used

In the display example, the parent definition simply dumps out the contents of the array

This is not how the final display is supposed to look for the assignment, but it can be used for debugging

If a subclass does override a virtual method, the method for the most specific type is used

Inheritance and Separate Compilation

When a subclass and its parent class are in separatemodules, the subclass module must be remadewhenever the parent class module is.

Makefile:

RearQueueInfo.o: QueueInfo.o RearQueueInfo.cc ...<TAB>g++ -c RearQueueInfo.cc -o RearQueueInfo.o

Failure to do this can cause bizarre behavior.

Inheritance Pitfalls (;-)Mutant Marsupials Take Up Arms Against Australian Air Force

As virtual reality simulators assume larger roles in helicopter combat training, programmers have gone to great lengths to increase the realism of their scenarios, including detailed landscapes and - in the case of the Northern Territory's Operation Phoenix- herds of kangaroos (since disturbed animals might well give away a helicopter's position).

The head of the Defense Science & Technology Organization's LandOperations/Simulation division reportedly instructed developers tomodel the local marsupials' movements and reactions to helicopters.

Inheritance Pitfalls (cont'd)

Being efficient programmers, they just re-appropriated some codeoriginally used to model infantry detachment reactions under thesame stimuli, changed the mapped icon from a soldier to a kangaroo,and increased the figures' speed of movement.

EnemyInfantrypositiontypespeedarmament

. . .

Kangaroo

Inheritance Pitfalls (cont'd)

Eager to demonstrate their flying skills for some visiting Americanpilots, the hotshot Aussies "buzzed" the virtual kangaroos in lowflight during a simulation.

The kangaroos scattered, as predicted, and the visiting Americans nodded appreciatively... then did a double-take as the kangaroos reappeared from behind a hill and launched a barrage of Stinger missiles at the hapless helicopter.

Easy remedy: Make the armament attribute privateand specify public inheritance.

A Better Design

DesertObject

positiontypespeed

. . .

KangarooEnemyInfantry

armament

Inheritance Hierarchy Example: Symbolic Differentiation

Symbolic differentiation (taking the derivative of anexpression) can be accomplished with expressions trees.

E.g., the derivative of x*(x+4)-5 = 2x+4

-

*

+

5

X

X 4

An expressiontree for x*(x+4)-5

Rules for Symbolic Differentiation

d(A-B) = d(A) - d(B)

d(A+B) = d(A) + d(B)

d(A*B) = A*d(B) + d(A)*B

d(Constant) = 0

d(x) = 1

Transforming the Expression Tree

-

*

+

5

X

X 4

-

+

*

0

*

X +

0

1 +

1 0 X

4

4

Apply derivationrules

Rules for Arithmetic Simplification

A - 0 ⇒ A

A + 0 ⇒ A

A * 1 ⇒ A

1 * A ⇒ A

Simplifying the Expression Tree

-

+

*

0

*

X +

0

1 +

1 0 X 4

+

X +

X 4

Apply simplificationrules

Basic Data Flow

Expression Trees

Differentiate

Simplify

However, there needs to be a wayto convert textual expressions to expressions trees, and vice versa.

Parsing

Parsing is the process of converting input expressionsinto expression trees.

It first must recognize the individual components:operators, variables, and constants (called tokens):

Equations Tokenizer Tokens

ExpressionTreee Builder

Expression Trees

Parser

Total Data Flow

Expression Trees

Differentiate

Simplify

Parser

Unparser

Equations

OOutput

Potential Data Classes

Input Stream

Token

Token Stream

Expression Tree

Expression Tree Node

Output Stream

Potential Algorithm Classes

Main

Parser

Differentiator

Simplifier

Unparser

Expression Tree Class

An expression tree suggests a natural hierarchy amongexpression tree nodes:

Node

OperatorNode

Leaf Node

BinaryOperator

UnaryOperator Constant Variable

Minus Add Sub Mult Div Exp

An "is-a"hierarchy

Inheritance and "Is-a" Hierarchies

Is-a hierarchies should be implemented through inheritance because:

Common properties can be factored out and defined only once (e.g. Printing)

New items can be added with minimal effort Rest of program can be written to operate on a generic

type Expr and ignore details of actual expressions The program documents itself by being organized to

mirror real-world objects

Deep vs. Shallow Hierarchies

A deep hierarchy: A shallow hierarchy:

A deep hierarchy yields more opportunity for reuse,but it may be difficult to follow code.

A shallow hierarchy indicates objects do not havemuch commonality.

A good design will balance depth and breadth.