1 / 46

Object Oriented Programming

Object Oriented Programming. Egar 2008 Recitation 9. Private / Protected Inheritance. Why?. Unlike public inheritance (that means “is-a”), private and protected inheritance mean “has-a” or “is-implemented-in-terms-of”.

basil
Download Presentation

Object Oriented Programming

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


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

  2. Private/Protected Inheritance 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. 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. 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. OOP Etgar 2008 – Recitation 9

  6. 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 {…}; 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. 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. OOP Etgar 2008 – Recitation 9

  9. Multiple Inheritance 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? 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. 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). 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()? 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. OOP Etgar 2008 – Recitation 9

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

  16. Virtual Bases 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! 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; // Ok • ta.Text::_scr; // Ok • ta.Text::OnScreenObj::_scr; // Ok 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. 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. 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. 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: • 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? • The same question for for GasPoweredVehicles. 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. OOP Etgar 2008 – Recitation 9

  24. The Bridge Pattern • We create two distinct hierarchies: • ABCVehicle has derived classes LandVehicle, WaterVehicle, etc. • ABCEngine 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. 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. OOP Etgar 2008 – Recitation 9

  26. Exceptions Error-handling mechanism 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? 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. 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. 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. 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. OOP Etgar 2008 – Recitation 9

  32. 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; • } 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. 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. 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. OOP Etgar 2008 – Recitation 9

  36. 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; • } 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). 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(). 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 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. 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. 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. 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 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. 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). 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.) 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. OOP Etgar 2008 – Recitation 9

More Related