Presentation is loading. Please wait.

Presentation is loading. Please wait.

OPERATOR OVERLODING.

Similar presentations


Presentation on theme: "OPERATOR OVERLODING."— Presentation transcript:

1 OPERATOR OVERLODING

2 Objectives Operator Overloading Type Conversion New Style Casts and RTTI(Run time type Information)

3 Overloading an operator means programming an operator to work on operands of types it has not yet been designed to operate. Overloading Operators—The Syntax: Operators are overloaded by writing operator-overloading functions. These functions are either member functions or friend functions of that class whose objects are intended as operands of the overloaded operator. Operator overloading functions are very similar to the member functions and friend functions. The only thing peculiar about them is their name. The names of operator-overloading functions are composed of the keyword operator followed by the symbol of the operator being overloaded. We can overload all the C++ operators except the following: (i) class member access operator(., .*) (ii) scope resolution operator (::) (iii) size operator (sizeof) (iv) conditional operator(?:)

4 Overloading Operators—The Syntax:
The syntax for member functions that overload a given operator is as follows: Member functions that overload operators can be private, protected, or public. The prototype of the operator-overloading function specifies a return type. The keyword operator follows the return type. This is followed by the symbol of the operator being overloaded. Finally, a pair of parentheses containing the formal arguments is specified.

5 Overloading Operators—The Syntax:
The syntax for a friend function that overloads a given operator is as follows: Operator-overloading function can be defined and used as a member function. (See Example 1) Operator-overloading function can be defined as a friend function. (See Example 2).

6 Overloading Operators—The Syntax:
Defining operator overloading using member function Example1: class <class name> { <return type> operator <op> (<argumentlist>); //prototype }; <return type> <classname> ::operator <op> (<argumentlist>)//definition { //Function body } Where return type is the type of value returned by the specified operation. operator op is the function name. Operator functions must be either member functions or friend functions.

7 Overloading Operators—The Syntax:
Defining operator overloading using friend function Example2: class <class name> { friend <return type> operator <op> (<argumentlist>); //prototype }; return type operator <op> (<argumentlist>)//definition //Function body } Where return type is the type of value returned by the specified operation. operator op is the function name.

8 Differences between member function and friend function w. r
Differences between member function and friend function w.r.to operator overloading A basic difference between them is that a friend function will have only one argument for unary operators and two for binary operators, while a member function has no arguments for unary operators and only one for binary operators. The friend function takes one argument more than member function because the invoking object appears as an explicit parameter to the friend function whereas in member functions it is passed as an implicit parameter.

9 The process of operator overloading involves the following steps:
Create a class that defines the data type to be used in the overloading. Declare the operator function operator op() in the public part of the class. It may be either a member function or a friend function. Define the operator function to implement the required operations. Overloaded operator functions can be invoked by expressions such as: op x or x op : for unary operator x op y : for binary operators

10 // overloading unary minus class space { int x; int y; int z; public :
void getdata(int a, int b, int c); void display(void); //friend void operator-(space &s); // declaration void operator-();// using member function };

11 void space :: getdata(int a, int b, int c)
{ x=a;y=b;z=c; } void space ::display(void) cout<<x; cout<<y; cout<<z; void space:: operator-() x=-x; y=-y; z=-z;

12 int main() { space S; S.getdata(10,-20,30); cout<<"S:"; S.display(); -S; cout<<"S"; return 0; } output

13 To overload unary minus using friend function
friend void operator-(space &s); // declaration void operator -(space &s) // definition { s.x=-s.x; s.y=-s.y; s.z=-s.z; }

14 overloading binary operators to add two complex numbers
c=sum(A,B) // functional notation c=A+B // arithmetic notation overloading + operator to add two complex numbers: class complex { float x;//real part float y;//imaginary part public: complex(){};// constructor 1

15 complex (float real, float imag) //constructor 2
{ x=real;y=imag; } complex operator+(complex); void display(void); };

16 complex complex::operator+(complex c)
{ complex temp; temp.x=x+c.x; temp.y=y+c.y; return(temp); } void complex::display(void) cout<<x<<"+j"<<y<<"\n";

17 int main() { complex C1,C2,C3; C1=complex(2.5,3.5); C2=complex(1.6,2.7); C3=C1+C2; cout<< "C1=";C1.display(); cout<<"C2=";C2.display(); cout<<"C3=";C3.display(); return 0; }

18 C1=2.5+i3.5; C2=1.6+i2.7; C3=4.1+i6.2; The operator+() operates in the following way: it receives only one complex argument explicitly it returns a complex type value it is a member function of complex C3=C1+C2; // invokes operator+() function C1 takes the responsibility of invoking function. C2 is the argument object The statement is equivalent to C3=C1.operator+(C2);// usual function call temp.x=x+c.x; c.x refers to object C2 and x refers to object C1, since data members of C1 are accessed directly.

19 OVERLOADING BINARY OPERATOR USING FRIENDS
The complex number program can be modified as follows: 1.Replace the member function declaration by the friend function declaration friend complex operator+(complex, complex); 2.Redifine the operator function as follows complex operator+(complex a, complex b) { complex temp; temp.x=a.x+b.x; temp.y=a.y+b.y; return(temp); }

20 in this case the statement
C3=C1+C2 is equivalent to C3=operator+(C1,C2); Reason for using overloading using friend function: Suppose A and B are the objects of the same class then, A=B+2; // will work for the member function &friend function A=2+B; //will not work for member function , but will work for //friend function, since left-hand operand is responsible for invoking the member function.

21 Compiler Interpretation of Operator-Overloading Functions
The compiler interprets operator-overloading functions is shown : s3=s1+s2; // s1,s2 and s3 are objects of the class string If the operator overloading function has been declared as a member function, then the following interpretation is satisfied: s3=s1.operator+(s2); If the operator overloading function has been declared as a friend function, then the following interpretation is satisfied: s3=operator+(s1, s2); However, we must note that the operator-overloading functions can be called directly from within the application programs : The benefit of overloading the operator will not be felt if the overloaded operators are directly called in this manner.

22 Manipulating string using operators
There are no operators for manipulating the strings. In order to copy one string to another , the programmer must first determine its length and allocate the required amount of memory. C++ allows us to create our own definitions of operators that can be used to manipulate the strings very much similar to the decimal numbers. We can manipulate the strings using string class as follows: For example , we shall able to use statements like: string3 = string1 + string2

23 Example illustrating the applications of overloaded operators
#include <iostream.h> #include <string.h> class string { char *p; int len; public: string () { len = 0; p=0; } //create null string string (char *s) len=strlen(s); p=new char[len+1]; strcpy(p,s); }

24 friend string operator + (string &s, string &t);
friend string void show(string s); }; string operator + (string &s , string &t) { string temp; temp.len=s.len+t.len; temp.p=new char[temp.len+1]; strcpy(temp.p,s.p); strcat(temp.p,t.p); return (temp); }

25 void show (string s) { cout<<s.p<<endl;} void main() string s1 = "New"; // string s1(“New”); string s2 = "Delhi"; string s3; clrscr(); s3=s1+s2; show(s1); show(s2); show(s3); getch(); }

26 Operator overloading becomes mandatory under the following circumstances:
1. Objects of the class acquire resources dynamically during run time and no two objects should share the same copy of the resource. Example: string s1(“abc”), s2; s2=s1; 2. Objects of the class acquire some resources dynamically during run time and no two objects should share even different copies of the resource. s2=s1; // should not compile at all The solution is to declare the function to overload the assignment operator in the private section of the class. This will produce an compile time error. 3. Objects need to be passed as parameters in function templates and the operators being used on template class objects within the template functions should work in the same way on objects of the class. 4. Change in the implementation of the class forces an undesirable change in its interface in turn necessitating the rewriting and recompiling of the application programs.

27 Operator overloading becomes mandatory under the following circumstances:
5. The default action of the dynamic memory management operators (new and delete) are unsuitable for the class being designed. By default, the new operator allocates the amount of memory requested, and also stores the amount of memory allocated in the memory itself. In memory critical applications, overloading the new operator can prevent a huge wastage of memory. By default, the new operator simply allocates memory for the object whose type is passed as an operand to it. To prevent the class from having more than one object, subsequent calls to the new operator should not create more objects, but merely return the address of the object that was created in response to the first call to the new operator. 6. Overloading provides better readability of code.

28 Rules for Operator Overloading
New operators cannot be created: New operators (such as **) cannot be created. Example: class A { public: void operator **(); //illegal attempt to create a new operator }; 2. Meaning of existing operators cannot be changed: Any operator-overloading function (member or friend) should take at least one operand of the class of which it is a member or friend. Thus, it is not possible to change the manner in which an existing operator works on operands of fundamental types (char, int, float, double). { public: friend int operator + (int, int); //illegal attempt to modify the behavior of operators In case of member functions, this condition is automatically enforced because the address of the calling object is implicitly passed as a parameter to it. However, in case of friend functions, the library programmer needs to take extra care. By ensuring that at least one operand of an operator-overloading function must be of the class type, the compiler ensures that the meanings of the existing operators cannot be changed.

29 Rules for Operator Overloading
Some of the existing operators cannot be overloaded: The following operators cannot be overloaded: :: (scope resolution) . (member selection) .* (member selection through pointer to member) ?: (conditional operator) sizeof (finding the size of values and types) typeid (finding the type of object pointed at) Some operators can be overloaded using non-static member functions only: = (Assignment operator) () (Function operator) [] (Subscripting operator) -> (Pointer-to-member access operator) These operators cannot be overloaded using friend or static functions

30 Rules for Operator Overloading
Number of arguments that an existing operator takes cannot be changed: Operator overloading functions should take the same number of parameters that the operator being overloaded ordinarily takes. For example, the division operator takes two arguments. Example: class A { public: void operator / (); //illegal attempt to modify the no. of arguments }; 6. Overloaded operators cannot take default arguments: An illegal attempt to assign a default value to an argument of an operator-overloading function causes a compile-time error. public: void operator / (int =0); //illegal attempt to assign a default value to opeartor overloaded function };

31 Rules for Operator Overloading
7. It is highly imprudent to modify the values of the operands that are passed to the operator-overloading functions. Example: class string { char *cstr; long int len; public: string operator + (string &); }; string string :: operator + (string &ss) this -> cstr=NULL; //BUG: left-hand parameter changed // rest of the function ss.cstr->=NULL ; //BUG } To guard against this mishap, the operator-overloading function can be declared.

32 Rules for Operator Overloading
To guard against this mishap, the operator-overloading function can be declared: class string { char *cstr; long int len; public: string operator + (const string &) const; };

33 Overloading Various Operators
Overloading increment and decrement operators (prefix and postfix): The prototype and definition of the operator-overloading function for the class Distance is shown in the example: The operator-overloading function should be public because it will mostly be called from within functions that are not members of the class Distance. It should not be a constant member function since it will certainly modify the value of at least one of the data members of the calling object. First, the increment operator works (since it is in prefix notation). The explicit call to the constructor creates a nameless object of the class distance by passing the incremented value of feet and the unaltered value of inch as parameters. The operator-overloading function returns the nameless object thus constructed.

34 Overloading Various Operators
Example: Overloading increment operator for distance class in prefix notation class distance { int feet; float inch; public: distance () { feet=inch=0;} distance (int x, float y) { feet=x; inch=y;} // rest of the class distance operator ++(); }; distance distance:: operator ++ () return distance(++feet, inch); } If d1 and d2 are the 2 objects of the class distance , then the statement: d2=++d1; Is interpreted by the compiler as: d2=d1.operator++();

35 Overloading Various Operators
If the call to the operator-overloading function is on the right-hand side of the assignment operator, the values of the returned object will expectedly be copied to the object on the left. An additional operator-overloading function to overload the increment operator can be defined in postfix notation. Example: Overloading increment operator for distance class in postfix notation class distance { public: // rest of the class distance operator ++(int); }; distance distance:: operator ++ (int) { return distance(feet++, inch); }

36 Overloading Various Operators
The constructor gets called before the increment operator executes because the increment operator has been purposefully placed in postfix notation. Thus, a nameless object with the initial values of the calling object is created. The increment operator increments the value of feet data member of the calling object. Finally, the nameless object constructed earlier with the initial values of the calling object is returned. If the call to this operator-overloading function is on the right-hand side of the assignment operator and there is an object of the class distance on its left, then the object on the left will get the initial values of the object on the right. The value of the object on the right will alone be incremented. These two operator-overloading functions convincingly duplicate the default action of the increment operator on intrinsic types.

37 Overloading Various Operators
If we provide an operator-overloading function for the increment operator in prefix notation, we must provide one for the postfix notation also. Decrement operators are overloaded in the same way as the increment operators. If d1 and d2 are the 2 objects of the class distance , then the statement: d2=d1++; Is interpreted by the compiler as: d2=d1.operator++ (0); //integer 0 If the compiler finds a exact matching prototype for postfix form, it compiles without warning errors. However, if it finds prototype for prefix form only it gives warning but still compiles with distance::operator+(). i.e., the compiler first looks for a function with an integer as a formal parameter.

38 Overloading Various Operators
Overloading unary minus and unary plus operator: The unary minus operator can be overloaded through a member function. (The operator can be overloaded by a friend function also.) Example: class A { int x; public: A(int=0); A operator –(); // or friend A operator –( A &) }; A A::operator-() // A operator – (A &Aobj) { return A(-x); // or return A (-Aobj.x) ; }

39 Overloading Various Operators
Overloading arithmetic operators: The syntax for overloading the arithmetic operators through member functions is as shown: <return type> operator <arithmetic symbol> (<parameter list>); An object that will store the value of the right-hand side operand of the arithmetic operator will appear in the list of formal arguments. The left-hand side operand will be passed implicitly to the function since the operator-overloading function will be called with respect to it. 2. The syntax for overloading the arithmetic operators through friend functions is as shown: friend <return type> operator <arithmetic symbol> (<parameter list>); Objects that store the values of the left-hand side and the right-hand side operands of the arithmetic operator will appear in the list of formal arguments.

40 Overloading Various Operators
Overloading arithmetic operators: How to overload the addition operator for the class Distance is as shown : distance d1(7,8), d2(4,9),d3; d3=d1+d2; This can also be done through either by member function or by friend function. This code works fine if the right-hand side operand of the addition operator is an object of class Distance. However, if it is a float-type value, then the preceding function will not work. Example: d3=d1+9.5; //will not work Because, the compiler will interpret this statement as: d3= d1.operator+(9.5);

41 Overloading Various Operators
Overloading arithmetic operators: However, introducing a suitable constructor that converts from float to Distance solves the problem. class distance { public: distance (float ); distance operator +(distance); }; distance:: distance( float p) { feet= (int) p; inch=(p-feet)*12; } However, if the left-hand side operand is of float type, the member function given in Listing 8.20 is replaced with a friend function. (See Listing 8.22).

42 Overloading Various Operators
Overloading arithmetic operators: However, if the left-hand side operand is of float type, for example: d3=9.5+d1; //will not work for member function Because, the compiler will interpret this statement as: d3= 9.5.operator+(d1);//illegal the member function given in previous example is replaced with a friend function. class distance { public: distance (float ); friend distance operator +(distance, distance); }; distance:: distance( float p) { feet= (int) p; inch=(p-feet)*12; }

43 Overloading Various Operators
The friend function given in previous example tackles all three conditions as follows: Both the left-hand side and the right-hand side operands are objects of class Distance: The operator-overloading function is called straight away without any prior conversions. The right-hand side operand is a float-type value while the left-hand side operand is an object of class Distance: The right-hand side operand is first converted into an object of the class Distance by the constructor and then the operator-overloading function is called. The left-hand side operand is a float-type value while the right-hand side operand is an object of class Distance: The left-hand side operand is first converted into an object of the class Distance by the constructor and then the operator-overloading function is called.

44 Overloading Various Operators
Where both operands are float-type values, the operator-overloading mechanism will not be invoked at all. Instead, the float-type values will simply get added to each other. For the class Distance, there is no function that converts a float-type value to an object of class Distance. The constructor that takes a float-type value as a parameter and initializes the object with it will be called. This is despite the fact that the object is being created and initialized by two separate statements. Such a constructor is called an implicit constructor. Having both a friend function and a member function will lead to ambiguity errors.

45 Overloading Various Operators
Overloading assignment operator: The assignment operator is a binary operator. If overloaded, it must be overloaded by a non-static member function only. Thus, the syntax for overloading the assignment operator is as shown : class_name & operator = (class_name &); By default, the compiler generates the function to overload the assignment operator if the class designer does not provide one. This default function carries out a simple member-wise copy. For example: Example: class A { public: &A operator = (A&); }; A & A::operator =(A & rhs) { *this=rhs; return *this; } In most cases, this default assignment operator is sufficient. However, there are cases where this default behaviour causes problems if the copy constructor is not defined. (See Listing 8.30). Pg 236 further explanation required

46 In most cases, the default assignment operator is sufficient
In most cases, the default assignment operator is sufficient. For classes that acquire resources dynamically, default causes problem. String s1(“abcd”); String s2= s1; The conclusion is that the assignment operator must be defined for a class whom the copy constructor is defined. Example String (const String &); // copy constructor String & operator = (const String &); String String :: operator = (const String & ss) { if this != &ss) {if(cStr != NULL) {delete[] cStr; cStr = NULL;len=0; }

47 Overloading Various Operators
Overloading assignment operator: String & string ::operator =(string & ss) { if (this!=&ss) { if (cstr!=NULL) { delete [] cstr; cstr=NULL; len=0; } if (ss.cstr!=NULL) { len=ss.len; cstr=new char[len+1]; strcpy(cstr,ss.cstr); } return *this;

48 (i)If LHS.cStr =NULL and RHS.cStr =NULL
If LHS.cStr =NULL, then the first inner ‘if’ fails and the corresponding if block does not execute. If RHS.cStr =NULL then the second inner ‘if’ fails and the block does not execute. The entire function does not do anything except that it returns the calling object by reference. The value of LHS operand remains unchanged.

49 (ii)If LHS.cStr =NULL and RHS.cStr !=NULL
If LHS.cStr =NULL, then the first inner ‘if’ fails and the corresponding if block does not execute. If RHS.cStr =!NULL then the second inner ‘if’ (if(ss.cStr!=0)) succeeds and the corresponding ‘if’block executes. It does the following: (i) correctly sets the value of len member of the calling object to be equal to the length of the memory block that will hold a copy of the string at which ‘cStr’ member of the RHS object is pointing. (ii) allocates just enough memory to hold a copy of the string at which the cStr member of the RHS object is pointing and makes cStr of LHS object point at it Copies the string at which the cStr of RHS object is pointing in to the memory block at which the cStr of LHS object is pointing.

50 (iii) If LHS. cStr. =NULL and RHS
(iii) If LHS.cStr !=NULL and RHS.cStr =NULL then the first inner ‘if’ succeeds and the corresponding if block executes. It deallocates the memory the block at which cStr of LHS object points, sets its value to NULL and sets the value of the ‘len’ member of LHS object to ‘0’. If RHS.cStr=NULL then the second inner ‘if’ fails and the corresponding if block does not execute. If LHS.cStr !=NULL and RHS.cStr !=NULL then the first inner block succeeds and executes.

51 It deallocates the memory the block at which cStr of LHS object points, sets its value to NULL and sets the value of the ‘len’ member of LHS object to ‘0’. If RHS.cStr!=NULL then the second inner ‘if’ succeeds and the corresponding if block executes. It does the required things. The preceding function accepts the argument as a const reference and returns the calling object by reference – to test and safeguard against self-assignment. The if condition ‘this == &ss’ tests to find out whether an object is being equated with itself or not.

52 An object may be get equated as
String s1 ; s1 = s1; or String s1; String &s2 = s1; s2 = s1; Each of the above will cause an extension of the function to overload the assignment operator. In each of the cases ‘if’ evaluates to true. For such circumstances the operator overloading function has been designed to remain unexecuted. This is necessary because in case of self assignment no action is necessary. Unnecessary allocation-deallocation should be avoided. The function has been designed to return by reference – to prevent chaining operation from

53 being inefficient, that is, to ensure an efficient execution of statements such as :
String s1, s2, s3; s3= s2 = s1; interpreted as s3.operator = (s2.operator = (s1) ); suppose s2= s2 = s1; suppose it is returned by value and not by reference. Then value of s2 is created in stack and its address is different from that of s2. When the assignment operator executes for the second time, reference variable ‘ss’ refers to this copy and not to s2 itself. When the library programmer wants to overload the ‘assignment’ operator and may not want to share even different copies of the same object.

54 A derived class object can be assigned to a base class object but the reverse is not true.
A A1 ; B B1; A1=B1; //OK B1= A1; //ERROR! the data members exclusively in B1 will remain unchanged and may no longer match with rest of the members of ‘B1’. Hence the compiler prevents! If the class designer desires, he may provide an assignment operator function to the derived class. public: B& operator = (const A&); //to enable B1=A1

55 Overloading Various Operators
Overloading assignment operator: In most cases, this default assignment operator is sufficient. However, there are cases where this default behaviour causes problems if the copy constructor is not defined. Example: class string { char *cstr; int len; public: string () { len = 0; p=0; } //create null string string & operator = (string &); }; String & string ::operator +(string & ss) { if (this!=&ss)

56 Overloading Various Operators
Overloading relational operators Relational operators are binary operators. 1. The syntax for overloading them through member functions is given below: <return type> operator <relational symbol> (<parameter list>); An object that will store the value of the right-hand side operand of the relational operator will appear in the list of formal arguments. The left-hand side operand will be passed implicitly to the function since the operator-overloading function will be called with respect to it. The expression: obj1 <relational symbol> obj2 will be interpreted as: obj1.operator <relational symbol> (obj2) 2. The syntax for overloading relational operator using friend function is as follows: friend <return type> operator <relational symbol> (<parameter list>); Objects that store the values of both the left-hand side and the right-hand side operands of the relational operator will appear in the list of formal arguments.

57 Overloading Various Operators
Overloading relational operators Suppose d1,d2 are the objects of the class distance then the following code must be compiled successfully : if (d1>d2) cout<<“greater than “ else cout<<“less than”; For this, we must overload the ‘>’ operator for the distance class . The expression: d1>d2 Will be interpreted as d1.operator > (d2)

58 Overloading Various Operators
Overloading relational operators How to overload the greater than relational operator for the class Distance is shown in Listing. Example: enum bool {false, true}; class distance { public: // rest of the distance bool operator > (distance); //member function }; bool distance:: operator > ( distance d) { if (feet*12+inch> d.feet*12+d.inch) return true; else return false; }

59 Overloading Various Operators
Overloading relational operators The code mentioned in the previous example works fine if the right hand side operand is an object. However, if it is a float type value, for example, the expression . d1>6.5; //will not compile The compiler will interpret this expression as: d1.operator > (6.5); In order make the above expression to work, a suitable constructor which converts float to distance is must be defined under distance class. However, if the left-hand side operand is of float type, for example: 9.5>d1; //will not work for member function To solve this problem, the member function given in previous example is replaced with a friend function. Therefore , upon using the friend function, all the 3 conditions can be tackled. If both the definitions, i.e., member as well as friend function is present in a class definition for overloading relational operator, the compiler will be confused . This will lead to an ambiguity error.

60 Overloading Stream-Insertion and Stream-Extraction Operators
Overloaded << and >> operators Overloaded to perform input/output for user-defined types To be consistent with the IO library , the operator should take ostream& or istream& as its first parameter and a reference to a const object of the class type as its second parameter Left operand of types ostream & and istream & Must be a non-member function because left operand is not an object of the class For example: cin>>A1; // A1 is an object of class A Is interpreted as: operator >>(cin,A1); Must be a friend function to access private data members

61 Overloading Stream-Insertion and Stream-Extraction Operators
The syntax for overloading the insertion operator is shown: class A { public: friend ostream & operator << (ostream &, A&); // rest of class A }; The syntax for overloading the extraction operator is shown: public: friend istream & operator >> (istream &, A&);

62 Overloading Stream-Insertion and Stream-Extraction Operators
The objects of the classes istream and ostream are passed and returned by reference in the preceding functions. The copy constructor and the assignment operator have been declared as protected members in both the classes istream and ostream. This prevents two objects from undesirably sharing even different copies of the same stream. For example following statements will throw compile time errors : ostream out=cout; //ERROR istream in = cin; //ERROR There is a compulsion to return by reference. If the object is returned by value, then a separate object is created in the stack. A call to the copy constructor is dispatched with respect to it and the object returned by the operator-overloading function is passed as a parameter. However, the copy constructor is a protected member. Therefore, the object must be returned by reference and not by value.

63 Example Program:Overloaded << and >> operators
class PhoneNumber { private: char areaCode[ 4 ]; // 3-digit area code and null char exchange[ 4 ]; // 3-digit exchange and null char line[ 5 ]; // 4-digit line and null public: friend ostream &operator<<( ostream&, const PhoneNumber & ); friend istream &operator>>( istream&, PhoneNumber & ); }; ostream &operator<<( ostream &output, const PhoneNumber &num ) output << "(" << num.areaCode << ") "<< num.exchange << "-" << num.line; return output; // enables cout << a << b << c; }

64 Overloaded << and >> operators
istream &operator>>( istream &input, PhoneNumber &num ) { input >> num.areaCode; // input area code input >>num.exchange; // input exchange input>>num.line; // input line return input; // enables cin >> a >> b >> c; } void main() PhoneNumber phone; // create object phone cout << "Enter phone number \n"; cin >> phone; cout << "The phone number entered was: " << phone << endl;}

65 Program Output Enter phone number : 800 555 1212
The phone number entered was: (800) Program Output

66 Overloading Various Operators
Overloading subscript operator: The subscript operator [] is normally used to access array elements. This operator can be overloaded to enhance the existing functionality of C++ arrays. Thus, the syntax for overloading the subscript operator is as shown : class <class name> { public: <return type> operator [] (<parameter list>); };

67 Example: Overloading [] operator
const int SIZE=10; class array { private: int arr[SIZE]; public: array() int i; for(i = 0; i < SIZE; i++) { arr[i] = i; } } int &operator[](int i) if( i > SIZE ) { cout << "Index out of bounds" <<endl; // return first element. return arr[0]; } return arr[i];

68 int main() { array A; cout << "Value of A[2] : " << A[2] <<endl; cout << "Value of A[5] : " << A[5]<<endl; cout << "Value of A[12] : " << A[12]<<endl; return 0; } When the above code is compiled and executed, it produces the following result: Value of A[2] : 2 Value of A[5] : 5 Index out of bounds Value of A[12] : 0

69 Overloading Various Operators
Overloading subscript operator: The subscript operator [] is normally used to access array elements. This operator can be overloaded to enhance the existing functionality of C++ arrays. Thus, the syntax for overloading the subscript operator is as shown : class <class name> { public: <return type> operator [] (<parameter list>); }; <return_type> <class_name> operator[] <param_list> {// statements }

70 class String { public: char& operator[] (const int) ;// for non-const objects char& operator[] (const int) const;//for const objects }; char& String ::operator[] (const int p) { return cStr[p] ;} char& String ::operator[] (const int p) const The function returns the corresponding element by reference. Because the subscript operator might be used on LHS of assignment operator also.

71 s[1] = ‘x’ ; // assign ‘x’ to second char of s
If you use the first function for the constant object like const String s(“abcd”); cout <<s[1];//ERROR . Hence we introduced a second function. Also s[1] = ‘x’; //compiles To prevent this we should make the return type reference. The formal argument of the function that overloads the ‘subscript’ operator can be of any type such as int, char, float, double.

72 Overloading Various Operators
Overloading assignment operator: The subscript operator [] is normally used to access array elements. This operator can be overloaded to enhance the existing functionality of C++ arrays. Thus, the syntax for overloading the subscript operator is as shown : class <class name> { public: <return type> operator [] (<parameter list>); };

73 Overloading ‘new’ and ‘delete’ operators
The ‘new’ and ‘delete’ operators are usually sufficient for most programs but there might be cases wherein you want to overload them as well. Some important points are: • You can overload these operators globally or you can overload them for specific classes. If you overload using member function for a class then we say that you have overloaded only for that specific class. If overloading is done outside a class (i.e. it is not a member function of a class), the overloaded ‘new’ and ‘delete’ will be called anytime you make use of these operators (within classes or outside classes). This is global overloading. • Be careful if you overload ‘new’ and ‘delete’ globally (because there might be other parts of your program which rely on the normal operation of these operators). Usually programmers do not overload them globally.

74 Overloading ‘new’ and ‘delete’ operators
The default action of the dynamic memory management operators (new and delete) are unsuitable for the class being designed. By default, the new operator allocates the amount of memory requested, and also stores the amount of memory allocated in the memory itself. In memory critical applications, overloading the new operator can prevent a huge wastage of memory. By default, the new operator simply allocates memory for the object whose type is passed as an operand to it. To prevent the class from having more than one object, subsequent calls to the new operator should not create more objects, but merely return the address of the object that was created in response to the first call to the new operator. Overloading provides better readability of code.

75 Overloading ‘new’ and ‘delete’ operators
The syntax for overloading ‘new’ and ‘delete’ are: void* operator new (size_t n) {     //allocate memory and return the address (a void pointer) } void operator delete (void *p) {     //free the memory space pointer to by the pointer ‘p’ } You will notice that the parameter for ‘new’ is: size_t n; size_t is a numerical data type defined by the system to specify memory size in bytes. Type size_t is an implementation dependent unsigned integral type defined in <stddef.h>. For instance if you use ‘new’ to create a character, the value of n (i.e. the argument passed to ‘n’) will be 1. If you pass a ‘double’ quantity then the value of ‘n’ will be 8 (you needn’t worry about this). The ‘new’ operator should return a void pointer while the ‘delete’ operator will pass a void pointer as argument. A void* does not mean anything. It is a pointer, but the type that it points to is not known. It's not that it can return "anything". A function that returns a void* generally is doing one of the following: It is dealing in unformatted memory. This is what operator new and malloc return: a pointer to a block of memory of a certain size. Since the memory does not have a type (because it does not have a properly constructed object in it yet), it is typeless. IE: void. It is an opaque handle; it references a created object without naming a specific type. Code that does this is generally poorly formed, since this is better done by forward declaring a struct/class and simply not providing a public definition for it. Because then, at least it has a real type. It has explicit documentation telling you what type(s) that you can use the pointer for.

76 New and Delete operators
The behavior of these operators can be altered for operands of specific class types. If the operators are overloaded for specific class, then the functions that overload are called when the class type is passed as a parameter to these operators. Otherwise the global new and delete operators are called. If ‘new’ is overloaded in class ‘X’ and not in ‘Y’ , then X* Xptr = new X; //overloaded new where as Y * Yptr = new Y; // global new void * operator new(size_t); //prototype void *<class_name> :: operator new(size_t size) { //definition of function }

77 void * operator new[](size_t); //prototype
void *<class_name> :: operator new[](size_t size) { //definition of function – for array } static void operator delete(void*, size_t); //prototype for delete void <class_name> :: operator delete(void * p, size_t size) { //definition of function } static void operator delete[](void*, size_t); //prototype for delete void <class_name> :: operator delete[](void * p, { //definition of function } size_t size)

78 The new and delete functions must be static
The new and delete functions must be static. Their prototypes need not be prefixed with ‘static’. The compiler treats these as ‘static’. The return type of the ‘new’ must be ‘void *’. The returned value is the address of the memory block. It should take at least on formal argument ‘size_t’. class A { int x; public : void * operator new(size_t); } ; #include”A.h” void * A :: operator new(size_t size) { cout<< sizeof(A)<<endl; cout<<size <<endl; void *p = ::operator new(size); return p; }

79 #include “A.h” void main() { A * Aptr = new A; } // output 4 4
Class designer will insert necessary code to overload ‘new’ operator and to allocate required amount of memory and then to return the address of the captured memory. The type ‘size_t’(essentially an unsigned integer) is a defined type capable of containing the largest piece of memory that can be allocated. ‘size’ will contain the number of bytes needed to hold the object being allocated.

80 The return type in ‘delete’ must be void, as it does not return anything. Its first argument should be of type void*. The address of the memory being deleted is passed to it. The second argument is ‘size_t’. class A { int x; public : void operator delete (void * const, const size_t); } ; #include”A.h” void A :: operator delete (void * const p, const size_t size) { cout<< p<< endl ; cout<< sizeof(A)<<endl; cout<<size <<endl; ::operator delete(size); }

81 #include “A.h” void main()
{ A * Aptr = new A; cout<<Aptr<<endl; delete Aptr;} output :OxCCCCCC OxCCCCCC ‘new’ and ‘delete’ functions are static by default. The compiler places a call to constructor (destructor) immediately after(before) the call to ‘new’ (‘delete’) operator. A * Aptr = new A ; is translated as A* Aptr =A :: operator new(sizeof(A)); A :: A(Aptr) ;// nameless object created and constructor called for that object.

82 The statement delete Aptr; is translated as
A:: ~A(Aptr); //destructor called for nameless object A:: operator delete (Aptr, sizeof (A) ); //nameless object destroyed

83 The program below overloads the ‘new’ and ‘delete’ operators globally.
void* operator new(size_t n) { cout<<endl<<"overloaded new"; void *ptr; ptr = ::operator new(n); return ptr; } void operator delete(void *p) {cout<<endl<<"overloaded delete"; ::operator delete p ; int main( ) {int *p = new int; *p=20; cout<<"\n The value is : "<<*p; //value of 20 delete p; cout<<"\n The value after deleting is : "<<*p; //some invalid value return 0; The output will be: overloaded new The value is : 20 overloaded delete The value after deleting is :

84 The C++ standard library comes with a set of predefined new and delete operators. The most important ones are these: void* operator new(size_t) ; void operator delete(void*); void* operator new[](size_t) ; void operator delete[](void*); The first two allocate/deallocate memory for an object, the latter two for an array of objects. If you overload operator new, you should always also overload the matching operator delete, even if you never intend to call it. The reason is that, if a constructor throws during the evaluation of a new expression, the run-time system will return the memory to the operator delete matching the operator new that was called to allocate the memory to create the object in. If you do not provide a matching operator delete, the default one is called, which is almost always wrong. If you overload new and delete, you should consider overloading the array variants, too.

85 Overloading pointer-to-member(->) operator (Smart pointer)
What are smart pointers? Actually, smart pointers are objects which behave like pointers but do more than a pointer. These objects are flexible as pointers and have the advantage of being an object (like constructor and destructors called automatically). A smart pointer is designed to handle the problems caused by using normal pointers (hence called smart). What are the common problems we face in C++ programs while using pointers? In case of ordinary pointers, there is no guarantee that the pointer being used is pointing at valid block of memory. Memory management. Consider following code: char* pName = new char[1024]; SetName(pName); … … if(null != pName) { delete[] pName; }

86 Overloading pointer-to-member(->) operator (Smart pointer)
How many times have we found a bug which was caused because we forgot to delete pName. It would be great if someone could take care of releasing the memory when the pointer is not useful . What if the pointer itself takes care of that? Yes, that’s exactly what smart pointers are intended to do. Let us write a smart pointer and see how we can handle a pointer better.

87 Overloading pointer-to-member(->) operator (Smart pointer)
class Person { int age; char* pName; public: Person(): pName(0),age(0) } Person(char* pName, int age): pName(pName), age(age) ~Person() void Display() printf("Name = %s Age = %d \n", pName, age); };

88 Now we shall write the client code to use Person.
void main() { Person* pPerson = new Person("Scott", 25); pPerson->Display(); delete pPerson; } Now look at this code, every time we create a pointer, we need to take care of deleting it. This is exactly what we want to avoid. We need some automatic mechanism which deletes the pointer. One thing which strikes to us is a destructor. But pointers do not have destructors, so what? Our smart pointer can have one. So we will create a class called SP which can hold a pointer to the Person class and will delete the pointer when its destructor is called. Hence our client code will change to something like this: void main() { SP p(new Person("Scott", 25)); p->Display(); // Dont need to delete Person pointer.. }

89 Note the following things:
We have created an object of class SP which holds our Person class pointer. Since the destructor of the SP class will be called when this object goes out of scope, it will delete the Person class pointer (as its main responsibility); hence we don’t have the problem of deleting the pointer. One more thing of major importance is that we should be able to call the Display method using the SP class object the way we used to call using the Person class pointer, i.e., the class should behave exactly like a pointer.

90 Smart pointer implementation
class SP { private: Person* pData; // pointer to person class public: SP(Person* pValue) : pData(pValue) } ~SP() // pointer no longer requried delete pData; Person& operator* () return *pData; } Person* operator-> () return pData; };

91 Note the following things:
The main responsibility of smart pointer class is to hold a pointer to the Person class and then delete it when its destructor is called. It should also support the interface of the pointer.

92 Type Conversion – Class to Basic
The constructor handles the task of converting basic types to class types very well. But you cannot use constructors for converting class types to basic data types. Instead, you can define an overloaded casting operator(type conversion operator) that can be used to convert a class data type into a basic data type. The general form of an overloaded casting operator function is shown below. This function is also known as a conversion function. The casting operator function should satisfy the following conditions: •It must be a class member. •It must not specify a return type. •It must not have any arguments. The object that invokes this function has its members directly accessible since this is a member function.

93 class DistConv { private: int kilometers; double meters; nbsp; const static double kilometersPerMile; public: // This function converts a built-in type (i.e. miles) to the // user-defined type (i.e. DistConv) DistConv(double mile) // Constructor with one // argument double km = kilometersPerMile * mile ; // converts miles to //kilometers kilometers = int(km); // converts float km to //int and assigns to kilometer meters = (km - kilometers) * 1000 ; // converts to meters } DistConv(int k, float m) // constructor with two // arguments kilometers = k ; meters = m ; // ********Conversion Function************ operator double() // converts user-defined type i.e. // DistConv to a basic-type { // (double) i.e. meters double K = meters/1000 ; // Converts the meters to &nsp; // kilometers K += double(kilometers) ; // Adds the kilometers return K / kilometersPerMile ; // Converts to miles void display(void) cout << kilometers << " kilometers and " << meters << " meters" ; }; // End of the Class Definition const double DistConv::kilometersPerMile = ; int main(void) DistConv d1 = 5.0 ; // Uses the constructor with one argument DistConv d2( 2, 25.5 ); // Uses the constructor with two arguments double ml = double(d2) ; // This form uses the conversion function // and converts DistConv to miles cout << "2.255 kilometers = " << ml << " milesn" ; ml = d1 ; // This form also uses conversion function d1.display(); cout << " = " << ml << " milesn" ; Output 2.255 kilometers = miles 8 kilometers and meters = 5 miles Type Conversion – Class to Basic

94 Type Conversion – Class to Class
Now that we have understood how to convert basic data types to class types and vice-versa, it is time to learn how to convert objects of one class type to another class type. The conversion between objects of different classes can be done using either a one-argument constructor or a conversion function. The choice depends upon whether the conversion routine has to be declared in the source class or in the destination class. To illustrate, consider a program that contains two classes: A and B. Also consider the statement: object_A = object_B; In the above statement, object_B of type B is converted to type A and assigned to object_A. Therefore, object_B is the source and object_A is the destination.

95 Type Conversion – Class to Class
For the conversion, the user can use either a conversion function or a constructor with one argument, depending on whether it is specified in the source class or the destination class. In other words, if class B handles the conversion, it will hold a conversion function. On the other hand, if class A carries out the conversion, it will do that through a constructor that takes an argument of type class B. Note that only one of the two conversion routines should be specified; the compiler will yield an error if both are specified since it will not be able to figure out which routine to call.

96 Type Conversion – Class to Class
class Kilometers { private: double kilometers; public: Kilometers(double kilometers): kilometers(kilometers) {} void display() cout << kilometers << " kilometeres"; } double getValue() return kilometers; };

97 Type Conversion – Class to Class
class Miles { private: double miles; public: Miles(double miles) : miles(miles) {} void display() cout << miles << " miles"; } operator Kilometers() return Kilometers(miles* ); Miles(Kilometers kilometers) miles = kilometers.getValue()/ ; };

98 Type Conversion – Class to Class
int main(void) { /* * Converting using the conversion function */ Miles m1 = 100; Kilometers k1 = m1; m1.display(); cout << " = "; k1.display(); cout << endl; /* * Converting using the constructor */ Kilometers k2 = 100; Miles m2 = k2; // same as: Miles m2 = Miles(k2); k2.display(); m2.display(); } Output 100 miles = kilometeres 100 kilometeres = miles


Download ppt "OPERATOR OVERLODING."

Similar presentations


Ads by Google