Presentation is loading. Please wait.

Presentation is loading. Please wait.

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

Similar presentations


Presentation on theme: "OOP Etgar 2008 – Recitation 91 Object Oriented Programming Egar 2008 Recitation 9."— Presentation transcript:

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

2 OOP Etgar 2008 – Recitation 92 Private / Protected Inheritance

3 OOP Etgar 2008 – Recitation 93 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.

4 OOP Etgar 2008 – Recitation 94 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.

5 OOP Etgar 2008 – Recitation 95 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 friend s 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.

6 OOP Etgar 2008 – Recitation 96 Code Example class B { public:void pub(); protected:void prot(); private:void priv(); }; class pubD: public B{…}; class protD: protected B{…}; class privD: private B{…};

7 OOP Etgar 2008 – Recitation 97 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.

8 OOP Etgar 2008 – Recitation 98 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.

9 OOP Etgar 2008 – Recitation 99 Multiple Inheritance

10 OOP Etgar 2008 – Recitation 910 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?

11 OOP Etgar 2008 – Recitation 911 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.

12 OOP Etgar 2008 – Recitation 912 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).

13 OOP Etgar 2008 – Recitation 913 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()?

14 OOP Etgar 2008 – Recitation 914 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.

15 OOP Etgar 2008 – Recitation 915 Ambiguity Resolution To resolve this ambiguity we can: –Use explicit qualification c.Shape::draw(); –Use the using-declaration class Shape…{ using Shape::draw; }; c.draw();// Calls c.Shape::draw()

16 OOP Etgar 2008 – Recitation 916 Virtual Bases

17 OOP Etgar 2008 – Recitation 917 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!

18 OOP Etgar 2008 – Recitation 918 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;// Ok ta.Text::_scr;// Ok ta.Text::OnScreenObj::_scr; // Ok

19 OOP Etgar 2008 – Recitation 919 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.

20 OOP Etgar 2008 – Recitation 920 Initialization In regular inheritance, each class initializes its immediate base classes. With virtual inheritance, the most derived class must initialize it.

21 OOP Etgar 2008 – Recitation 921 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 A class D : public B class E : public D class 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.

22 OOP Etgar 2008 – Recitation 922 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.

23 OOP Etgar 2008 – Recitation 923 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.

24 OOP Etgar 2008 – Recitation 924 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.

25 OOP Etgar 2008 – Recitation 925 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.

26 OOP Etgar 2008 – Recitation 926 Exceptions Error-handling mechanism

27 OOP Etgar 2008 – Recitation 927 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?

28 OOP Etgar 2008 – Recitation 928 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.

29 OOP Etgar 2008 – Recitation 929 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.

30 OOP Etgar 2008 – Recitation 930 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.

31 OOP Etgar 2008 – Recitation 931 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.

32 OOP Etgar 2008 – Recitation 932 Example class popOnEmpty {};// Exceptions are objects, class pushOnFull {};// need to define the classes int Stack::pop() {// Stack from recitation 1 if (_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; }

33 OOP Etgar 2008 – Recitation 933 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.

34 OOP Etgar 2008 – Recitation 934 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.

35 OOP Etgar 2008 – Recitation 935 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.

36 OOP Etgar 2008 – Recitation 936 Example int 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; }

37 OOP Etgar 2008 – Recitation 937 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).

38 OOP Etgar 2008 – Recitation 938 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().

39 OOP Etgar 2008 – Recitation 939 Exception Declaration The () part in catch is called exception declaration. It can be either type declaration or an object declaration. …catch (popOnEmpty) {// Type declaration cout << "Caught popOnEmpty\n"; } catch (pushOnFull e) {// Object declaration cout << 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.

40 OOP Etgar 2008 – Recitation 940 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 catch es.

41 OOP Etgar 2008 – Recitation 941 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.

42 OOP Etgar 2008 – Recitation 942 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

43 OOP Etgar 2008 – Recitation 943 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.

44 OOP Etgar 2008 – Recitation 944 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 ).

45 OOP Etgar 2008 – Recitation 945 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.)

46 OOP Etgar 2008 – Recitation 946 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.


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

Similar presentations


Ads by Google