Presentation is loading. Please wait.

Presentation is loading. Please wait.

Department of Computer Science and Engineering, HKUST 1 HKUST Summer Programming Course 2008 Operator Overloading ~ and User Defined Conversions.

Similar presentations


Presentation on theme: "Department of Computer Science and Engineering, HKUST 1 HKUST Summer Programming Course 2008 Operator Overloading ~ and User Defined Conversions."— Presentation transcript:

1 Department of Computer Science and Engineering, HKUST 1 HKUST Summer Programming Course 2008 Operator Overloading ~ and User Defined Conversions

2 2 What is operator overloading?  What is operator overloading? Operator overloading is an example of polymorphism … it extends to overloading concept to operators, lets you assign multiple meaning to C++ operators.

3 3 Operator overloading can … (1)  The simplest application : beautifying function calls. Arithmetic operators (+, -, *, /) Relational operators (>, <, ==) Directly “cin” and “cout” the object ( >) Indexing a collection ([])  This allow user of the class to treat the class as primitive types.  Operator overloading allows generic algorithm to treat user object as primitive. More about this later … when we cover template.

4 4 Operator overloading can … (2)  Here are some applications that operator is necessary to implement the desired function. Function objects, using the bracket operator  Particularly useful in generic algorithm, again. assignment operator (=), already covered in the “class” lecture. Smart Pointers (*, ->), which help reduce bug related to memory leak. Customized memory allocation.  Contact me if you’re interested, we don’t have time for this during lecture.

5 5 Two tastes of operator overloading  Operator as member function  Operator as global function

6 6 After operator overloading …  If the Money class overloaded the + operator: 1: Money a(2.5); 2: Money b(3.5); 3: Money c = a + b;  Notice, two Money objects can be added together

7 7 Different types of operators  Operators are classified by the number of inputs they take: The negation operator is unary. (e.g. int y = -x) The addition operator is binary. (e.g. a = b + c) The :? (i.e. selection operator) is ternary  BUT! It cannot be overloaded.  Different types of operator have different type of syntax.

8 8 Unary Operator How to write as member function  For unary operators: 1: class Value { 2: public: 3: Value(int _value) : value(_value) {} 4: Value operator-() { 5: return Value(-value); 6: } 7: private: 8: const int value; 9: };

9 9 Unary Operator as Member Function Code Explained  Code Explained Line 4: It declares the operator- with no argument as a member function.  There is no need for additional parameter. Since the calling object is the only object that is needed. Line 5: It creates the new object and return the object to the caller.  Different ways of calling this method: Value v(5); -v (apply as operator) v.operator-(); (call operator method)

10 10 Unary Operator as Member Function BAD Example  How would you write the ! (logical not) operator for the Value class? bool Value::operator!() { return true; }  This is a BAD example, why?  Never overload an operator that does NOT intuitively interpretable. That’s a very BAD practice.

11 11 Binary Operator Implemented as Member Function  Binary Operator as member function class Value { public: Value(int _value) : value(_value) {} Value operator+(const Value& v) { return Value(this->value + v.value); } private: const int value; };

12 12 Binary Operator Another example  How would you write the * (multiply) operator for the Value class? Value Value::operator*(const Value& another) { return Value(this->value * another.value); }  What will happen if I write: Value v2(2), v3(3), v4(4); Value v(v2 + v3 * v4);// v.value = 14 The precedence and associativity rule CANNOT be overridden.

13 13 More about associativity of operator  In mathematics, if you write 1 – 2 – 3, you intuitively understand that as (1 – 2) – 3.  From another perspective, why it could NOT be interpreted as 1 – (2 – 3)? Because it is understood, from our culture.  The implicit rule in the above is associativity.  The subtraction operator is left associative.  The assignment operator is right associative.

14 14 Member Operator Function Additional Notes  Although in most examples, operator member function are implemented inline. This is NOT necessary. (They’re done so to save space :P)  It is NOT required that the operator to work on the same datatype, for example, this is valid: class Value { public: Value operator+(const int& v) { return Value(this->value + v); } };

15 15 Implementing Operator as Global Function  You can also define operator in another way: class V { public: V(int v) { this->v = v; } int v; }; V operator+(const V& v1, const V& v2) { return V(v1.v + v2.v); }  Notice, now the operator is NO longer a member function, it is a global function.

16 16 Friend Global function- Access Protection  If the operator do need to access privileged (i.e. private/protected) data members, then it is not possible to access the data members directly in a global function  Example: class V { public: V(int value) : v(value) { } int getValue() const { return v; } private: int v; }; V operator+(const V& v1, const V& v2) { return V( v1.getValue() + v2.getValue() ); }

17 17 Friend Global function- Workaround Access Protection  It is tedious and inefficient to use the accessors in every operator. To make it easier, we can declare the operator as a friend function, so that we can access the private field directly.  Example: class V { public: friend V operator+(const V& v1, const V& v2); private: int v; }; V operator+(const V& v1, const V& v2) { return V(v1.v + v2.v); }

18 18 Friend Global function- Workaround Access Protection  This is not a bad practice of declarating an operator as a friend function Since an operator should work closely with the class. It is more efficient, because we don’t need to call accesor method(s).

19 19 Why implementing operator as global function? (1)  Allows other developers to develop operator without the need to modify source code of an object.  Example: class Money { public: Money(int value) { … } const char* getCurrencyCode() const; double getValue() const; // … }; Money operator+(const Money& m1, const Money& m2) { return Money(m1.getValue() + m2.getValue()); }

20 20 Why implementing operator as global function? (2)  It supports more flexible rules for implicit type conversion.  Example class Test { public: // Recall this is a type conversion constructor Test(int v); Test operator+(const Test& test) { … } … }; Test operator-(const Test& t1, const Test& t2);

21 21 Why implementing operator as global function? (3)  To see the flexibility:  Test t1, t2; t1 + t2: Valid t1 + 1 : Valid 1 + t1 : Invalid (The left operand is NOT an object) t1 - t2: Valid t1 - 1 : Valid 1 - t1 : Valid

22 22 cin/cout the object.  Idea: overload the operator >> for cin and the operator << for cout.  Syntax: ostream& operator<<(ostream& os, const Money& m) { os << m.getCurrencyCode() << “$” << m.getValue(); return os; } istream& operator>>(istream& is, Money& m) { string currencyCode; int value; char dollarSign; is >> currencyCode; m.setCurrencyCode(currencyCode); is >> dollarSign;// ignore this character is >> value; m.setValue(value); return is; }

23 23 Code Explained  Directly cin/cout is possible because the operator can be a global function. We have no way to modify the << operator if it must be a member function, and We do NOT need to access the privileged area of these streams, so that we don’t need to add friend declaration to the stream class  What is ostream, actually? ostream is the parent class for the cout object. It is also the parent class for ofstream object.  There is only ONE cout object throughout.  Therefore ostream CANNOT be copied, it must be passed by reference, both as an input parameter and as a return value.  Similar for istream, skipped

24 24 Operator Overloading: Point to note (1)  For everything covered above, if you don’t like operator overloading, you can do it with member functions alone.  If you define the operator+ to operates on the same type, (i.e. V operator+(const V& another) defines the += operator as well V& operator+=(const V& another) { (*this) = this->operator+(another); // equivalent to: (*this) = (*this) + another; return *this; } Many operators form a “group”, when you implement one, implements the other as well, they can be easily implemented.

25 25 Operator Overloading: Point to note (2)  You can do this (syntactically correct) V operator+(const V& v1, const V& v2) { return V( v1.getValue() - v2.getValue() ); }  Do NOT abuse operator overloading! For example, don’t use the operator+ to do subtraction, this will confuse your library user a lot.

26 26 More operators: Pre-increment /Post-increment operator  This is how the pre-increment operator is implemented. Value& Value::operator++() { ++v; return *this; }  This is how the post-increment operator is implemented. Value Value::operator++(int) { Value copy(*this); ++v; return copy; }  Notice the dummy int parameter in the post-increment version, it is a trick C++ used to differentiate pre and post increment operators, since they both can be overloaded. One should NOT use it or assume any value of it. A good practice is NOT even to name the variable.

27 27 More Operator: Increment Operators  The pre-increment operator should return a reference.  The post-increment operator has to return a COPY of the object that is BEFORE increment. Cannot return *this, must return an unchanged instance. Cannot return *this, and also, the return is NOT a reference (why?).

28 28 Container  Container are classes that are designed to store other data (or object). Linked List is an example of a container.  Using operator overloading, you can treat these container as simple as an array. Specifically, you can overload the index operator [].  The syntax is like this: (as a member function) int& Container::operator[](int index)  Why returns a reference? Because the user WILL modify the indexed value instead of simply reading it (e.g. a[3] = 7)

29 29 Index operator – const correctness.  Returning a reference does allow modification, so the function cannot be const (even if the member function itself do NOT modify the object).  As a result, the method cannot be called on a const reference. i.e. const Container a; int x = a[3]; // Cannot compile!  Solution: Define another member function: const int& operator[](int index) const;  Member function overloading allows const and non-const function to overload To be precise, the const-ness is a part of the signature of a member function in a class By default, from non-const instance, the non-const version is executed, otherwise the const version is executed.

30 30 Passing function to function  Sometimes, I want to pass a function to another function. Scenario: A sorting function wants to accept another function that compares two elements: So that it can sort differently, according to different input function.  Ascending order/ Descending order  Case sensitivity / Case insensitivity  There are TWO different ways to pass a function to another function. Function Pointer – an old method that was inherited from C programming days, or Function Object – a newer mechanism for passing a function

31 31 Function Pointers  A VERY brief idea of function pointer is given here. For in depth discussion, students are referred to C++ primer. #include using namespace std; void fun1(int x) { cout << ( x + 1) << endl; } void fun2(int y) { cout << (y-1) << endl; } int main(){ void(*p)(int) = fun1; p(1); p = fun2; p(1); return 0; }  Notice the blue line, it defined a function pointer named p and it points to fun. Then p can be used as if it is a function.

32 32 Function Object  Function Pointers are cubersome, isn’t it?  Let’s be object oriented, pass an object! class Compare { public: Compare(Mode compareMode = caseInsensitive ) { … } // return true if x < y bool operator()(const char* x, const char* y){ … } enum Mode { caseSensitive = 0, caseInsensitive = 1 } mode; };  Compare c1(Compare::caseInsensitive), c2(Compare::caseSensitive);  bool larger1 = c1(“aB”,”ab”); // larger1 = false  bool larger2 = c2(“aB”,”ab”); // larger2 = true

33 33 Smart Pointer (1)  Smart pointer is motivated by a primary need: I don’t want any memory leak bug. Many times, C++ bug is about memory.  Smart pointer are designed to automatically delete object that is no longer useful.  Key idea: Object on the stack are deleted automatically. + Object on the heap is NOT deleted automatically + I can write a customized destructor. = Write an object, contain the pointer, delete during destruction = automatically delete unwanted object.

34 34 Smart Pointer (2)  Because the smart pointer object represents a pointer, let’s override the common operator for a pointer.  Encapsulation! The raw pointer is protected in the private area, so that nobody can modify/delete it without being noticed.  Implementation Roadmap: First, a constructor, which takes a pointer to the object as parameter. Second, dereference operator, it should return a reference to the pointed object. Third, -> operator, it should return the true pointer. Fourth, destructor, it should delete the object pointed to by the pointer, if exist.

35 35 Smart Pointer (3) class V { public: V () { value = 100; } void setValue (int v) { value = v; } void print() const { cout << value << endl; } int value; };

36 36 Smart Pointer (4) class SmartPointer { public: SmartPointer(V* _ptr = NULL) : ptr(_ptr) { } V& operator*() { return * ptr;} // unary: dereference const V& operator*() const{ return * ptr; } V* operator->() {return ptr; } // This is a little bit strange. const V* operator->() const { return ptr; } ~SmartPointer() {if (ptr ) delete ptr; } private: V* ptr; };

37 37 Smart Pointer (5)  Do NOT use that at home.  The SmartPointer can ONLY point to object of type V. More about generic smart pointer next time.  The example smart pointer is NOT that smart. ++/--/== is not implemented  Use auto_ptr in C++ standard libraries. More about this when we talk about templates.


Download ppt "Department of Computer Science and Engineering, HKUST 1 HKUST Summer Programming Course 2008 Operator Overloading ~ and User Defined Conversions."

Similar presentations


Ads by Google