Top Banner
OOP Etgar 2008 – Recitation 9 1 Object Oriented Programming Egar 2008 Recitation 9
46

OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

Dec 20, 2015

Download

Documents

Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 1

Object Oriented Programming

Egar 2008Recitation 9

Page 2: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 2

Private/Protected Inheritance

Page 3: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 3

Why?• Unlike public inheritance (that means “is-

a”), private and protected inheritance mean “has-a” or “is-implemented-in-terms-of”.

• They are quite similar to composition (when an inner object is contained as data member in the outer object), but there are subtle differences.

Page 4: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 4

Composition• Inner object is called data member.• Data member can be accessed from

outside only if declared public.• Outer object can’t override data

member’s methods or access protected members.

• Outer object can contain several data members of one type.

Page 5: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 5

Private/Protected Inheritance

• Inner object is called base class subobject.• Subobject cannot be accessed from outside (and

derived pointer cannot be converted to private/protected base pointer, unless by methods or friends of the derived).

• Derived can access protected members of the subobject.

• Derived can override subobject’s methods.• Outer object contains only one base class

subobject.

Page 6: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 6

Code Exampleclass B {public: void pub();protected: void prot();private: void priv();};

class pubD : public B{…};

class protD : protected B{…};

class privD : private B{…};

Page 7: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 7

Access Levels• public inheritance:

– public parts of B remain public in pubD and protected remain protected in pubD.

• protected inheritance:– public and protected parts of B become protected

in protD.

• private inheritance:– public and protected parts of B become private in

privD.

• B’s private remains inaccessible to derived.

Page 8: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 8

When to Use?• Use composition whenever you can.• Use private/protected inheritance when you

have to:– If you need to override inherited virtual

method.– If you need access to protected members.

Page 9: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 9

Multiple Inheritance

Page 10: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 10

Why?• Recall the interface Shape from previous

lecture and imagine we have class MyCircle that implements circles (but not with Shape’s interface).

• We would like to implement a Circle with Shape’s interface while using existing code from MyCircle.

• Usually this is done with composition, but what if private inheritance is required?

Page 11: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 11

Multiple Inheritance• In C++ we can use multiple inheritance –

make a class inherit from more than one base.

class Circle: public Shape, private MyCircle {…};

• Circle now has Shape’s interface and all features of private inheritance from MyCircle.

• Class can inherit from any number of bases and in any combination of public/protected/private inheritance.

Page 12: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 12

Points• Pointer or reference to derived can be

implicitly converted to any of the bases.– Conversion to each base is considered equally

good.

• Subclass constructor initializes base classes in the order of their appearance from left to right (and destructor destroys in the reverse order).

Page 13: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 13

Ambiguities• What if two bases define functions with the same

name?class Shape { public: virtual void

draw(); };class MyCircle { public: void draw(); };class Circle: public Shape, private MyCircle

{…};// Circle doesn't

redefine draw()

Circle c;c.draw(); // Ambiguous –

Shape::draw() or

MyCircle::draw()?

Page 14: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 14

Overload Resolution?• Even if draw()’s parameter list were

different in bases, the call still would have been ambiguous.

• This is because overload resolution is not applied across different class scopes.

Page 15: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 15

Ambiguity Resolution• To resolve this ambiguity we can:

– Use explicit qualificationc.Shape::draw();

– Use the using-declarationclass Shape…{

using Shape::draw;};

c.draw(); // Calls c.Shape::draw()

Page 16: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 16

Virtual Bases

Page 17: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 17

The Dreaded Diamond• Continuing the Shape hierarchy:

class OnScreenObj {protected : Screen _scr…};

class Shape : public OnScreenObj {…};

class Text : public OnScreenObj {…};

class TextArt : public Shape, public Text {…};

• This poses a problem – in multiple inheritance each base is represented by its own subobject.

• But we don’t want the Shape part of TextArt to have different _scr than the Text part!

Page 18: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 18

Another Ambiguity• Moreover, since TextArt has two OnScreenObj

parts, we must specify which one we mean:

TextArt ta;ta._scr; //

Ambiguous – which _scr?ta.Shape::_scr; // Okta.Text::_scr;

// Okta.Text::OnScreenObj::_scr; //

Ok

Page 19: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 19

Virtual Inheritance• To specify that derived classes of Shape or

Text can share one copy of the base OnScreenObj, we can define it as virtual base:

class Shape : public virtual OnScreenObj {…};

class Text : virtual public OnScreenObj {…};

class TextArt : public Shape, public Text {…};

• Now TextArt has only one OnScreenObj subobject.

Page 20: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 20

Initialization• In regular inheritance, each class

initializes its immediate base classes.• With virtual inheritance, the most derived

class must initialize it.

Page 21: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 21

Initialization Example• For example, A is a virtual base of B, D (regularly) derives

from B, E from D and F from E.class B : virtual public Aclass D : public Bclass E : public Dclass F : public E

• When object of type B is created, A is initialized from B’s constructor, when object of type D is created – from D’s, and so on.

• Thus B, D, E, F‘s constructors must initialize A.A::A(int a=1):_a(a){}B::B(int a=1,b=2):A(a),_b(b){} D::D(int a=1,b=2,d=3):A(a),B(a,b){}E::E(int a=1,b=2,d=3,e=4):A(a),b(a,b),d(a,b,d){}…

• Note that all virtual base classes are created before all other base classes.

Page 22: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 22

Multiple Inheritance Alternatives

• Consider the following situation:Suppose you have land vehicles, water vehicles, air vehicles, and space vehicles .

• Suppose we also have different power sources: gas powered, wind powered, nuclear powered, pedal powered, etc.

• We could use multiple inheritance to tie everything together, but before we do, we should ask a few tough questions:

1. Will the users of LandVehicle need to have a Vehicle& that refers to a LandVehicle object? In particular, will the users call methods on a Vehicle-reference and expect the actual implementation of those methods to be specific to LandVehicles?

2. The same question for for GasPoweredVehicles.

Page 23: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 23

Multiple Inheritance Alternatives

• if both answers are "yes," multiple inheritance is probably the best way to go.

• If none or one of the answers are “no” consider the following alternatives.

• Also there are some considerations which will make you choose an alternative even if both answers are “yes”.

• The alternatives are the bridge pattern and nested generalization.

Page 24: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 24

The Bridge Pattern • We create two distinct hierarchies: • ABC Vehicle has derived classes LandVehicle,

WaterVehicle, etc.• ABC Engine has derived classes GasPowered,

NuclearPowered, etc. • Then the Vehicle has an Engine* (that is, an

Engine-pointer), and users mix and match vehicles and engines at run-time.

Page 25: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 25

Nested Generalization • We pick one of the hierarchies as primary and

the other as secondary, and you have a nested hierarchy.

• For example, if you choose geography as primary, Vehicle would have derived classes LandVehicle, WaterVehicle, etc.

• Those would each have further derived classes, one per power source type. E.g., LandVehicle would have derived classes GasPoweredLandVehicle, PedalPoweredLandVehicle, NuclearPoweredLandVehicle, etc.

Page 26: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 26

Exceptions

Error-handling mechanism

Page 27: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 27

Why?• Consider what happens when an error

occurs in a program that consists of separate modules.

• Often the action that needs to be taken depends on the calling module rather than on the module that found the error.– A string doesn’t know what to do if it cannot

allocate memory. The user of the string does.

• And what if the caller of the caller knows how to fix the error?

Page 28: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 28

Exceptions• Exceptions are program anomalies that

occur during runtime (out-of-memory, pop-on-empty-stack, division-by-zero, etc.).

• Exception handling is a mechanism that allows two separately developed modules to communicate when exception occurs.

Page 29: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 29

Throwing and Catching• A module that detects an error has

occurred signals it by throwing an exception of appropriate type.

• The module in the calling chain that knows how to handle the exception declares that by catching an exception of that type.– A pop() in Stack can throw popOnEmpty, and Stack’s

user can catch it and know that pop() didn’t succeed because it’s empty.

Page 30: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 30

Why Exceptions?• Exceptions:

– Separate exceptional logic from normal logic.– Supported by the compiler.– Can carry any amount of information from

thrower to the catcher.– Can be used in constructors.

• But impose runtime overhead.• Returning error codes is still used.

Page 31: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 31

throw• An exception is an object of some type.• The program part that has detected an

error that it cannot handle, throws an exception (which is an object) of some type.

• This is done using the throw expression.

Page 32: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 32

Exampleclass popOnEmpty {}; // Exceptions are

objects,class pushOnFull {}; // need to define the

classes

int Stack::pop() { // Stack from recitation 1if (_top_index == 0)

throw popOnEmpty(); // Used to be "return 0"return _contents[--_top_index];

}

void Stack::push(int el) {if (_top_index == _size)

throw pushOnFull(); // Used to be "return false"_contents[_top_index++] = el;return true;

}

Page 33: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 33

Example Notes• Notice that now push() doesn’t return a

value, and pop() returns only elements of the stack.

• Since throw throws an object, the corresponding class needs to be defined beforehand.

• It’s best to use separate classes for exceptions.

Page 34: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 34

throw Creates an Object• throw creates a temporary object of the

given type and “passes it on”.– Note the () in

throw pushOnFull();

This creates a pushOnFull object using the default constructor.

– Had class pushOnFull had a constructor with int parameter (for example), we could write:

throw pushOnFull(el);

– The handler would then know what element wasn’t pushed.

Page 35: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 35

Catching• To be handled, an exception needs to be

caught.• This is done using try-catch construct.• Operations that can throw exception are

enclosed in a try block, and following that block a series of catch clauses, each defining how to handle specific type of exception.

Page 36: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 36

Exampleint main() {

Stack s(10);

try {s.push(1);// More pops,

pushes, printouts, etc.} catch (popOnEmpty) {

cout << "Caught popOnEmpty\n";} catch (pushOnFull) {

cout << "Caught pushOnFull\n";}cout << "Done\n";return 0;

}

Page 37: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 37

catch Clauses• Each catch clause defines how to handle a

specific type of exception that might have occurred in the preceding try block.

• The clauses are examined top down until a matching catch is found.

• If none is found, the exception propagates to the caller.

• If a matching catch clause is found, its body is executed and execution resumes after the last catch (for that try block).

Page 38: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 38

Exception Propagation• Notice that a try-catch block only needs to

handle exceptions it knows how to “fix”.• Anything is doesn’t handle propagates to

the caller of that function.• When exception tries to propagate out of

main(), the STL terminate() function is called, which by default calls abort().

Page 39: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 39

Exception Declaration• The () part in catch is called exception declaration.• It can be either type declaration or an object

declaration.…catch (popOnEmpty) { // Type

declarationcout << "Caught popOnEmpty\n";

} catch (pushOnFull e) { // Object declarationcout << e.val() << " cannot be pushed\n";

}

• In object declaration the exception object that was thrown is given a name and can be accessed.

• This allows the exception object to carry additional information about the error.

Page 40: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 40

Catching Everything• If someone (main(), for example) wants to

handle any exception that can be thrown, it can use catch(...):

try {//…

} catch (...) {cout << "Unknown exception occurred\n";

}

• Obviously, it should come last in the list of catches.

Page 41: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 41

Catching by Reference• Exception declaration is much like function

parameter list.• In particular, we can catch exception objects by

reference:…catch (pushOnFull& e) {…}

• Otherwise the exception object is passed by-value into the catch clause.

• Using “catch-by-reference”:– Prevents unnecessary copying;– Allows changing the exception object;– Permits polymorphism.

Page 42: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 42

Exception Specification• How do we know which function throws exceptions

and what types?• Function exception specification is a comma-

separated list of exceptions the function might throw.int Stack::pop() throw(popOnEmpty);void Stack::push(int) throw(pushOnFull);

• This list is checked at runtime – if the function throws unspecified exception, the STL unexpected() function is called (which by default calls terminate()).

• Exception specification is part of functions interface:int Stack::pop() { // Err, must

match declaration

Page 43: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 43

Stack Unwinding• When an exception is thrown, the calling

functions exit one after another until a handler is found.

• During this process all the objects that were defined on stack (local – also called automatic – variables in these functions) are properly destroyed.

• This is called stack unwinding.

Page 44: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 44

Rethrow• If a handler doesn’t know how to fully

recover from an exception, it can rethrow it (after doing what it wanted).

• This is done by throw;…catch (popOnEmpty e) {

cout << "Can't pop";throw;

}

• The object rethrown is the original exception object (not the copy in catch).

Page 45: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 45

Exception Hierarchies• Since exceptions are objects, we can build

exceptions hierarchies.• For example, a base class Exception,

subclasses StackException and MathException, and two subclasses for StackExceptions – popOnEmpty and pushOnFull.

• All rules applying to base and derived apply here (catching derived instead of base, virtual functions with “catch-by-reference”, etc.)

Page 46: OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9.

OOP Etgar 2008 – Recitation 9 46

Constructors and Destructors

• Constructor can (and should) signal an error by throwing an exception.– In this case all data members and base class

subobjects constructed so far are properly destroyed.

• Destructor should never throw (or let out) an exception.– Destructors are called during stack unwinding,

and if it throws another exception (thus two exceptions will be active simultaneously), terminate() is called.