OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps:...

21
OBJECT-ORIENTED PROGRAMMING IN C++ Prepared by: B. R. Shakya

Transcript of OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps:...

Page 1: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

OBJECT-ORIENTED PROGRAMMING IN C++ Prepared by: B. R. Shakya

Page 2: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

CONTENTS Module 6: Operator Overloading Operator Overloading ...............................................................................................154

Introduction............................................................................................................154 Overloading Unary Operators................................................................................155 Overloading Binary Operators...............................................................................156 Overloading Binary Operators using Friend..........................................................158 Arithmetic Assignment Operators .........................................................................159 Limitations and Restrictions for Overloading Operators.......................................160

Data Conversion.........................................................................................................161 Conversion from basic type to basic type ..............................................................161 Conversion between Objects and Basic type .........................................................161 Conversion from class type to basic type ..............................................................162 Conversion from basic type to class type ..............................................................163 Example: Conversion between Strings and String Objects ..................................164 Conversion between objects of different classes ...................................................165 Conversion Routine in Source Objects: operator function ....................................166 Conversion Routine in Destination Objects: constructor function ........................168 Example: Complete Conversion ............................................................................169 One-argument Constructor or Operator Function? ................................................171

Page 3: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 154

Operator Overloading

Introduction Overloading operators is an important technique that has enhanced the power of

extensibility of C++. In C++, we can make the user defined data types of various ways which behave in

much the same way as the built in types. We also can add two variables of user-defined types with the same syntax that is applied to basic types, which provides the operators with a special meaning for a data type. The mechanism of giving such meaning to an operator is known as operator overloading.

Operator Overloading option for the creation of new definitions for most of the C++ operators.

It also helps to create provides a flexible a new language of our own type by the creative use of the function and operator overloading techniques.

Overloading can be done to all the C++ operators except Class member access operators (. , .*) Scope resolution operator ( :: ) Size operator (sizeof) Conditional operator ( ? : )

Overloading allows only the extendibility of the semantics of an operator but not change in syntax (grammatical rules).

When an operator is overloaded, its original meaning is not lost. Overloading the operators can be done with the help of a special function called

operator function. Syntax of operator function: return_type class_name :: operator sign(arglist) { // function body … }

Operator functions must be either member functions (non-static) or friend functions.

Basic difference between member function and friend function 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. (why?? Answer in next point)

The object used to invoke the member function is passed implicitly and so is available for the member function. But in friend function this is not the case.

Arguments in operator function may be passed either by value or by reference. The process of overloading involves the following steps:

1. Create a class that defines the data type that is to be used in the overloading operation.

2. Declare the operation function operator sign( ) in the public part of the class. It may either be a member function or a friend function.

3. Define the operator function to implement the required operations.

Here you have a table with a summary on how the different operator functions must be declared (Note: replace @ by the operator in each case)

Page 4: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 155

Overloading Unary Operators Unary operators act on only one operand. Example of unary operators are ++ , -- and the unary minus & unary plus.

Example Code (Overloading Unary Operators) /***Demonstration of Overloading Unary Operators***/ //unaryop.cpp #include <iostream.h> #include <conio.h>

class UnaryTest { int count; public: UnaryTest(int c=0) { count = c; } int getcount( ) { return count; } void display( ) { cout << count; } UnaryTest operator ++ ( ) // for prefix { return UnaryTest(++count); } UnaryTest operator ++ (int)// for postfix { return UnaryTest(count++); } UnaryTest operator -- ( ) // for prefix

Page 5: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 156

{ return UnaryTest(--count); } UnaryTest operator -- (int) // for postfix { return UnaryTest(count--); } }; int main( ) { clrscr( ); UnaryTest i1, i2 = 10, i3; cout << "...INITIALLY..."; cout << "\ni1 = " << i1.getcount(); cout << "\ni2 = "; i2.display(); ++i1; cout << "\n\n...After ++i1..."; cout << "\ni1 = " << i1.getcount(); i1++; cout << "\n\n...After i1++..."; cout << "\ni1 = " << i1.getcount(); --i2; cout << "\n\n...After --i2..."; cout << "\ni2 = "; i2.display(); i2--; cout << "\n\n...After i2--..."; cout << "\ni2 = "; i2.display(); i3=i1--; cout << "\n\n...After i3 = i1--..."; cout << "\ni3 = "; i3.display(); cout << "\ni1 = "; i1.display(); getch( ); return 0; }

Overloading Binary Operators Example: Overloading + operator using member functions

While going through Constructor & Destructor in Class and Object, we have seen that to add the members of objects of same class using a friend function with the statement

C = sum (A,B); where A, B and C are objects of same class. This functional notation can be replaced by a natural looking expression C = A + B; by overloading the + operator. Example Code (Overloading Binary Operators)

Page 6: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 157

/***Demonstration of Overloading Binary Operators***/ // vectors: overloading operators example using member function #include <iostream.h> #include <conio.h> class CVector { public: int x,y; CVector (int,int); CVector operator + (CVector); }; CVector::CVector (int a=0, int b=0) { x = a; y = b; } CVector CVector::operator + (CVector param) { CVector temp; temp.x = x + param.x; temp.y = y + param.y; return (temp); } int main ( ) { clrscr( ); CVector a (3, 1); CVector b (1, 2); CVector c; c = a + b; // (4, 3) cout << "(" << c.x << "," << c.y << ")"; getch( ); return 0; }

Let us have a closer look at the function operator + ( ) and see how operator overloading is operated. CVector CVector :: operator + (CVector param) { CVector temp; temp.x = x + param.x; temp.y = y + param.y; return (temp); }

We should note the following features of this function 1. It receives only one CVector type argument explicitly. 2. It returns a CVector type value 3. It is a member function of CVector.

Page 7: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 158

Overloading Binary Operators using Friend Friend function may be used in the place of member function for overloading a

binary operator. The only difference being that a friend function requires two arguments to be

explicitly passed to it, while a member function requires only one. The example binaryop.cpp can be modified be following changes

1. Replace the member function declaration by the friend function declaration friend CVector operator + (CVector, CVector);

2. Redefine the operator function as CVector operator + (CVector param1, CVector param2) { return CVector((param1.x + param2.x), (param1.y + param2.y)); } Thus, C = A + B; will be equivalent to C = operator + (A, B);

Example Code (Overloading Binary Operators using Friend) /**Demonstration of Overloading Binary Operators using friend**/ // vectors: overloading operators example using friend function #include <iostream.h> #include <conio.h> class CVector { public: int x,y; CVector ( ) { x = 0; y = 0; }; CVector (int,int); friend CVector operator + (CVector, CVector); }; CVector::CVector (int a, int b) { x = a; y = b; } /* CVector operator+ (CVector param1, CVector param2) { CVector temp; temp.x = param1.x + param2.x; temp.y = param1.y + param2.y; return (temp); } OR | | \ / \/ */

Page 8: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 159

CVector operator+ (CVector param1, CVector param2) { return CVector((param1.x + param2.x), (param1.y + param2.y)); } int main ( ) { clrscr( ); CVector a (3,1); CVector b (1,2); CVector c; c = a + b; //(4,3) cout << "(" << c.x << "," << c.y << ")"; getch( ); return 0; }

Arithmetic Assignment Operators Example: Overloading += operator

C++ allows us to combine arithmetic operation with the assignment operators. e.g. using x += y in place of x = x + y. Example Code (Overloading Arithmetic Assignment Operators) /*Demonstration of Overloading Arithmetic Assignment Operators*/ #include <iostream.h> #include <conio.h> class ArithAsign { public: int x; ArithAsign (int); ArithAsign operator = (ArithAsign); ArithAsign operator += (ArithAsign); }; ArithAsign :: ArithAsign (int a=0) { x = a; } ArithAsign ArithAsign :: operator = (ArithAsign param) { return ArithAsign(x = param.x); } ArithAsign ArithAsign :: operator += (ArithAsign param) { return ArithAsign(x += param.x); }

Page 9: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 160

int main ( ) { clrscr( ); ArithAsign a (3); ArithAsign b (1); a += b; //4 ArithAsign c; c = a; cout << a.x << endl; cout << c.x; getch( ); return 0; }

Limitations and Restrictions for Overloading Operators Only existing operators can be overloaded. New operators cannot be created. The overloaded operator must have at least one operand that is of user-defined type. Basic meaning of an operator can’t be changed. We can’t redefine the plus (+)

operator to subtract one value from the other. Overloaded operators follow the syntax rules of the original operators. They can’t be

overridden. Some operators can’t be overloaded. We can’t use friend functions to overload certain operators. However, member

function can be used to overload them. Unary operators, overloaded by means of a member function, take no explicit

arguments and return no explicit values, but, those overloaded by means of a friend function, take one reference argument (the object of the relevant class).

Binary operators overloaded through a member function take one explicit argument and those which are overloaded through a friend function take two explicit arguments.

When using binary operators overloaded through a member function, the left hand operand must be an object of the relevant class.

Binary arithmetic operators such as +, -, *, and / must explicitly return a value. They must not attempt to change their own arguments.

Operators that cannot be overloaded • Sizeof size of operator • . Membership operator • .* pointer-to-member operator • :: scope resolution operator • ? : conditional operator

Where a friend cannot be used

= assignment operator ( ) function call operator [ ] subscripting operator -> class member access operator

Page 10: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 161

Data Conversion We know that, if we use the data types interchangeably within certain limit; it is

possible due to automatic conversions though may involve some demotion or truncation of data. i.e. within certain rules, the type of data to the right of an assignment operator (=) is automatically converted to the type of the variable on the left.

e.g. int a; float b = 4.14; a = b; //here a will store 4

We also know that in C++, user can create his/her own data types as per needed. Now, a question may arise, WHAT happens when we try to make data conversion in

user defined data types?? Since the user defined data types are designed by us to suit our requirements, the compiler does not support automatic type conversion for such data types. If these situations arise then we need to design the conversion routines by ourselves.

There are three types of situations that might arise in the data conversion between incompatible types:

1. Conversion from basic type to basic type 2. Conversion from basic type to class type 3. Conversion from class type to basic type 4. Conversion from one class type to another class type

Conversion from basic type to basic type Example: void main( ) { int i; float f; i = 11; f = i/5; cout << f; // 2 f = float(i)/5; // int to float type conversion cout << f; // 2.2 }

Conversion between Objects and Basic type Why do we require the conversion between objects and basic types?

The compiler supports data conversion of only built-in data types supported by the language.

The user cannot rely on the compiler to perform conversion from user-defined data types to primitive data types and vice-versa.

The compiler does not know anything about the logical meaning of user defined data types.

Thus, to perform meaningful conversion, the user must supply the necessary conversion function. The conversion can be from user defined to basic data types and/or vice-versa.

Page 11: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 162

Where and How the conversion function should exist? To convert from a basic type to a user-defined type, the conversion function should

be defined in user-defined object’s class in the form of constructor. This constructor takes a single argument of basic data-type.

Syntax: Constructor(BasicType) { // steps to convert (Body) }

In the case of conversion from user- defined to basic type, the conversion function should be defined in user-defined object’s class in the form of the operator function. The operator function is defined as an overloaded basic data-type which takes no arguments. It converts the data members of an object to basic types and returns a basic type.

Syntax: operator BasicType( ) { // steps of conversion (body) }

Conversion from class type to basic type Example Code (Conversion from basic type to class type) //b2c_conv.cpp #include <iostream.h> #include <conio.h> class time { int hr; int min; public: time (int t = 0) { hr = t/60; min = t%60; } void display() { cout << hr << "hr " << min << "min."; } }; int main() { clrscr(); time t1;

Page 12: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 163

int duration = 100; t1 = duration; //type int converted to class type time t1.display(); getch(); return 0; }

Conversion from basic type to class type Example Code (Conversion from class type to basic type) /***Demonstration of conversion from class type to basic type***/ //c2b_conv.cpp #include <iostream.h> #include <conio.h> class Scale { const float MTF; //meter to feet int ft; float inches; float meter; public: Scale(int feet=0,float inch=0.0) : MTF(3.280833F) { float fractionfeet = inch/12; fractionfeet += float(feet); meter = fractionfeet/MTF; } void display() { cout << meter << "meters."; } void getvalue() { ft = 7; inches = 8.51949F; } operator float() const { float fractionfeet = inches/12; fractionfeet += float(ft); return fractionfeet/MTF; } };

Page 13: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 164

int main() { clrscr(); Scale s1; s1.getvalue(); float mtrs = float(s1); //uses conversion operator to change to meters cout << "\nUsing concept of conversion between class to basic types\n"; cout << mtrs << "meters." << endl; //for checking Scale s2 = Scale(7, 8.51949F); cout << "\nUsing concept of constructor\n"; s2.display(); getch(); return 0; }

Example: Conversion between Strings and String Objects

Here we are trying to demonstrate the use of one argument constructor and a converting function to show the conversion between Strings and String Objects.

The data conversion not only takes place during object creation and in assignment statements, but also in the case if arguments passed to operators (for instance, <<) or functions.

The incompatible arguments passed to a function as long as there exists a conversion function.

Example Code /***Conversion between Strings and String Objects***/ //strconv.cpp #include <iostream.h> #include <conio.h> #include <string.h> class string //user defined string class { char str[50]; public: string() //constructor1 { strcpy(str, " "); } string(char *mystr) //constructor2 {

strcpy(str, mystr); //source=mystr, //destination=str:- copying

}

Page 14: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 165

void display() { cout << str << endl; } //user defined to basic data type conversion operator char * ( )

//occurs when destination data item is char * type { return str; } }; int main() { clrscr(); //conversion from string of type char * to string object char str1[50] = "This is BIM third sem class."; string strcp; //uses constructor1 strcp = str1; //uses function 'string(char *mystr)' cout << "String1: "; strcp.display(); //conversion from object to char * type char * cpstr; string str2 = "We are senior students now."; cpstr = str2; //uses the function 'operator char * ()' cout << "\nString2: "; cout << cpstr; getch(); return 0; }

Conversion between objects of different classes C++ compiler itself does not support data conversion between objects of user-defined

classes. For this purpose, the data conversion methods can be used, like:

One-argument constructor Conversion function

The choice between these two methods for data conversion depends on whether the conversion function should be defined in the source object or destination object.

Consider the following skeleton code: ClassA objecta; ClassB objectb; … objecta = objectb;

Page 15: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 166

where objecta and objectb are the objects of classes ClassA and ClassB respectively. Here, the conversion method can be either defined in ClassA or ClassB depending on whether it should be a one-argument constructor or an operator function.

Conversion Routine in Source Objects: operator function The conversion routine in the source object’s class is implemented as an operator

function. In an assignment statement such as,

objecta = objectb; objectb is the cource object of the class ClassB and objecta is the destination object of the class ClassA.

The conversion function operator ClassA( ) exists in the source object’s class SYNTAX: //Destination object class class ClassA

{ // ClassA stuffs }; //Source object class class ClassB

{ private: // attributes of ClassB public: operator ClassA( ) //conversion operator function {

// stuffs for converting ClassB object to // ClassA object attributes

} … }; Example Code (Conversion routine in source object) //c2csrc.cpp #include <iostream.h> #include <conio.h> const float PI = 3.14159F; class Radian { float rad; public: Radian() //constructor1 { rad = 0.0; }

Page 16: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 167

Radian(float InitRad) //constructor2 { rad = InitRad; } float GetRadian() { return (rad); } void Display() { cout << "Radian = " << GetRadian(); } }; class Degree { float degree; public: Degree() { degree = 0.0; } //this function will be called if //we try to assign object degree to object of type radian operator Radian() { //converts degree to radian and //creates an object radian and then return, //here radian constructor1 is called return (Radian(degree * (PI/180.0))); } void Read() { cout << "Enter Degree: "; cin >> degree; } }; int main() { clrscr(); Degree deg; Radian rad; deg.Read(); rad = deg; //uses 'operator Radian()' rad.Display(); getch(); return 0; }

Page 17: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 168

Conversion Routine in Destination Objects: constructor function Example Code (Conversion routine in destination object) //c2cdest.cpp #include <iostream.h> #include <conio.h> const float PI = 3.14159F; class Degree { float degree; public: Degree() { degree = 0.0; } float GetDegree() { return (degree); } void Read() { cout << "Enter Degree: "; cin >> degree; } }; class Radian { float rad; public: Radian() //constructor1 { rad = 0.0; } Radian(Degree deg) //constructor2 { rad = deg.GetDegree() * (PI/180.0); } float GetRadian() { return (rad); } void Display() { cout << "Radian = " << GetRadian(); } };

Page 18: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 169

int main() { clrscr(); Degree deg; Radian rad; deg.Read(); rad = deg; rad.Display(); getch(); return 0; }

Example: Complete Conversion compconv.cpp shows the concept of defining conversion functions in the source or

object object’s class. angles in degrees can be converted to radians or angles in radians can be converted to

degrees. A class can have both conversion functions:

constructor function, and operator function.

A class can have any number of functions as long their signatures are different. Example Code (Complete Conversion) // compconv.cpp #include <iostream.h> #include <conio.h> #include <stdlib.h> const float PI = 3.14159F; class Radian { float rad; public: Radian() { rad = 0.0; } Radian(float InitRad) { rad = InitRad; } float GetRadian() { return (rad); }

Page 19: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 170

void Read() { cout << "Enter Radian: "; cin >> rad; } void Display() { cout << "Radian = " << GetRadian() << endl; getch(); } }; class Degree { float degree; public: Degree() { degree = 0.0; } Degree(Radian rad) { degree = rad.GetRadian() * 180.0 / PI; } float GetDegree() { return (degree); } operator Radian() { return (Radian(degree * PI / 180.0)); } void Read() { cout << "Enter Degree: "; cin >> degree; } void Display() { cout << "Degree = " << degree << endl; getch(); } };

Page 20: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 171

int main() { Degree deg; Radian rad; char ch; start: clrscr(); cout << " CONVERSION \n"; cout << "MenuBar\n"; cout << "\tD-egree to radian\n"

<< "\tR-adian to degree\n" << "\tE-xit\n"; cin >> ch; clrscr(); if (ch == 'D' || ch == 'd' || ch == 'R' || ch == 'r' || ch == 'E' || ch == 'e') { switch(ch) { case 'D': case 'd': deg.Read(); rad = deg; rad.Display(); goto start; case 'R': case 'r': rad.Read(); deg = rad; deg.Display(); goto start; case 'E': case 'e': exit (0); } } else { goto start; } return 0; }

One-argument Constructor or Operator Function? If the user-defined object is a source object, the conversion routine must be defined as

an operator function in the source object’s class. If the user-defined object is a destination object, the conversion routine must be

defined as one-argument constructor in the destination object’s class. If both the source and destination object are the instances of user-defined classes, the

conversion routine can be placed either in source object’s class as a operator function or in destination object’s class as a constructor function.

Page 21: OBJECT-ORIENTED PROGRAMMING IN C++ · ¾ The process of overloading involves the following steps: 1. Create a class that defines the data type that is to be used in the overloading

Operator Overloading

©2004 B.R.Shakya. 172

Assignment

1. When would you choose which conversion (one-argument constructor or operators function)? Explain Why?

2. What are the drawbacks of operator overloading and conversion? illustrate.