1 / 23

Operator Overloading: indexing

Operator Overloading: indexing. Useful to create range-checked structures: class four_vect { double stor[4]; // private member, actual contents of vector. … double& operator [ ] ( int j) { if (j < 0 || I > 3) throw index_error; // defined elsewhere

jordanl
Download Presentation

Operator Overloading: indexing

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. Operator Overloading: indexing • Useful to create range-checked structures: class four_vect { double stor[4]; // private member, actual contents of vector. … double& operator[ ] (int j) { if (j < 0 || I > 3) throw index_error; // defined elsewhere return stor[j]; }; Note: return type is a reference, so can be used on l.h.s

  2. Extending the meaning of subscripting • An associative array: class Assoc { // a map from strings to numbers struct Pair { // an inner class char* name; double val; Pair (char* n = “”, double v = 0) : name (n), val (v) { }; }; pair * contents; // Assoc is a set of pairs public: Assoc ( ) { }; // default constructor double& operator[ ] (const char*); // map string => number };

  3. Efficiency vs. privacy • Linear algebra package: vector class for 4-vectors, matrix class for 4-by-4 matrices • vector class redefines [ ] to do check index • matrix class redefines [ ] to check both indices • want to implement matrix * vector: • v2 [j] = S m[j][k] * v [k]; • 4 range-checks for every component, all redundant.

  4. Relaxing privacy: friends • A friend function can access private members of a class • a friend is declared in the class (cannot sneak in) class vector {... friend vector operator* (const matrix&, const vector&); • a function can be the friend of several classes class matrix {… friend vector operator*(const matrix&, const vector&); • A class can be a friend, so all its function members are. class quaternion { friend class matrix; …} • A friend is not a class member

  5. Efficient code class matrix { vector row [4]; public: … }; vector operator * (const matrix&m, const vector v) { vector res; for (int i = 0; i < 4; i ++) { res.stor[i] = 0; // stor is private data in a vector for (int j = 0; j < 4; j++) res.stor[j] += m.row[i].stor[j] * v.stor[j]; // row is private }; return res; };

  6. Packages and private information • In Ada, declare both types in same package. Package body has access to full declarations for both: package linear_algebra is type vector is private; type matrix is private; function “*” (m : matrix; v : vector) return vector; private type vector is array (1..4) of long_float; type matrix is array (1..4) of vector; -- code in body can use array representation of both. end linear_algebra;

  7. Inheritance • General mechanism for extending existing classes. • Specialization: an X is an A • A mammal is a vertebrate • a feline is a mammal • a cat is a feline • a persian is a cat • A persian has all the attributes of a feline, a mammal, and a vertebrate • A class hierarchy implements a sequence of Is-A relations

  8. Advantages of inheritance • Factorization: Common properties are grouped in a single class • code reuse : Descendant class (derived class) is defined incrementally over parent. • incrementalprogramming : New derived classes can be added without changing existing parents and siblings. • Polymorphism: Can describe collections of diverse objects belonging to a class hierarchy.

  9. Derivation class point { // base class int x, y; public: point () { x = 0; y = 0}; // basic constructor void move (int dx, int dy) { x += dx; y += dy}; } void display ( ) ; // put black dot on the screen. } class color_point: public point { // derived class int R, G, B; // in addition to hidden members x, y public: color_point ( ):point ( ) {R = 50; G = 50; B = 50;}; // call parent constr. void lighten (int w) { R -= w; G -=w; B -= w;}; void display ( ); // put colored dot on the screen // move is inherited, applies to color_points as well };

  10. Substitution rule • An object from a derived class can be used wherever an object from the base class is expected. point* p1 = new color_point ( ); • works because a descendant has all the attributes of the parent (possibly with different meanings). color_point* wrong = new point ( ); // error: incomplete object • but p1 can be coerced (cast) to a color_point, because it is one. • Formal definition: the Liskov substitutability principle

  11. inheritance and privacy • Private members of the parent class are not visible in (the methods of) the derived class. int color_point::abcisa ( ) {return x; }; // error • Constructor for parent is used to initialize parent data. Derived (…) : Parent (…) { …}; // rest of construction • Protected members are visible in descendants, but not outside.

  12. Polymorphism • Because of substitution rule, can have collection of various kinds of points: point* figure [100]; • To display collection, apply the appropriate display method to each: point::display () color_point::display () blinkling_point::display () • Could add discriminant to each object, to recognize its class • Best to use virtual methods.

  13. Virtual methods class parent { virtual void change (int x) … class child: public parent { virtual void change (int x) … // overrides parent operation class grandchild: public child { virtual void change (int x)… // overrides child operation parent* someone = … // can point to any member of family someone-> change () // the proper one for someone’s class

  14. Dynamic dispatching • If M is virtual, the call ptr -> m (..) must determine the actual nature of ptr, and invoke the proper method • Each class is described by a table of virtual methods (the vtable) • Each object carries a pointer to the vtable. • Each derived class inherits the table • each overriding modifies an entry in the table • Dynamic dispatching is an indirect call through an entry at a known position in the vtable.

  15. Overloading and dynamic dispatching • Overloading resolution is a compile-time process that applies to an expression in a context: that = this_one + the_other; // find right numeric type • dynamic dispatching is a run-time activity that applies to a reference: some_relative-> display (); // indirect call tommy.display ();// static resolution • overloading resolution may fail if call is ambiguous • dynamic dispatching succeeds because derived classes have all the virtual methods of ancestors.

  16. The profile of an overriding method class parent { virtual void method (int x); virtual void relation (parent x); class child: public parent { virtual void method (int x); // overrides inherited method virtual void method (double x); // different method Binary operations are not symmetric: virtual void relation (child x); // does not override parent relation virtual void relation (parent x); // overrides

  17. Abstract classes • Base class may not have enough attributes to create meaningful object: class shape { point anchor; int color [3]; virtual void display (); // can’t write anything here }; shape blob; // can’t do anything with it • If methods are declared abstract, cannot create objects of class: virtual void display ( ) = 0; // must be overridden

  18. A useful pattern: the factory • Need to create class hierarchy. • Need different versions of hierarchy on different platforms (e.g. Windows vs. Linux) • Need to minimize dependence on platform. • Solution: encapsulate “constructors” into an object: class maker { virtual class1* build_class1 (int) = 0; virtual class2* build_class2 (int) = 0; };

  19. Everything can be solved with indirection class win_maker: public maker { virtual class1* build_class1 (int){ ...}; // implementation virtual class2* build_class2 (int){…}; // on windows }; class linux_maker: public maker { virtual class1* build_class1 (int){ ...}; // implementation virtual class2* build_class2 (int){…}; // on RedHat 6.2 }; maker* factory = .. // build the proper one class1* thing1 = maker -> build_class1 (5);

  20. Multiple inheritance • Class can inherit from several parents: class abstract_stack { // algebraic definition public: void push (int x) = 0; ... }; class vector {…}; // sequential allocation class stack: public abstract_stack, public vector { public: void push (int x) { .. }; // use vector primitives }

  21. Multiple inheritance and overloading class A { … void draw ( ); }; class B { … void draw ( ); }; class C: public A, public B { ... void display ( ) { draw ( ); // ambiguous: 2 inherited methods A:: draw ( ); // OK };

  22. Replicated base classes class Root {… // some data members class A: public Root { … // inherits data members class B: public Root { … // inherits same data members class hybrid: public A, public B {… // two copies of data members of Root? class C: virtual public Root {… // single copy in children

  23. Other complexities • Additional run-time structures for dispatching: • Data members are concatenation of data members of parents • Vtable is concatenation of Vtable’s of parents. • Each operation needs to compute offset to find parent data members in descendant object. • Multiple inheritance best when it is interface inheritance, or when implementation is inherited from only one parent: • Java and Ada model: one parent, many interfaces. • Interfaces are abstract classes that only have operations • “inheriting from an interface is like inheriting a mortgage”

More Related