CS112: Object Oriented Programming Muhammad Salman Saeed Operator Arguments • the ++ operator is applied to a specific object, as in the expression ++c1 • What does this operator increment? • It increments the count data in the object of which it is a member • Since member functions can always access the particular object for which they’ve been invoked, this operator requires no arguments Operator Return Values • The operator++() function has a defect. You will discover it if you use a statement like this in main(): c1 = ++c2; • The compiler will complain. Why • Because ++ operator is defined to have a return type of void in the operator++() function, while in the assignment statement it is being asked to return a variable of type Counter • The normal ++ operator, applied to basic data types such as int, would not have this problem int x,y; y=10; x = y ++; class Counter{ int count; public: Counter() : count(0) {} int get_count() { return count; } Counter operator ++ (){ ++count; Counter temp; temp.count = count; return temp; } }; c1 count 2 0 1 c2 count Counter class Example main() { Counter c1, c2; cout << “\nc1=” << c1.get_count(); cout << “\nc2=” << c2.get_count(); ++c1; ++c1; c2 = ++c1; c2 =c1; cout << “\nc1=” << c1.get_count(); cout << “\nc2=” << c2.get_count() ; } Program Output c1=0 02 c2=0 c1=2 c2=2 Nameless Temporary Objects Counter temp; temp.count = count; return temp; main() { Counter c1, c2; cout << “\nc1=” << c1.get_count(); cout << “\nc2=” << c2.get_count(); ++c1; c2 = ++c1; cout << “\nc1=” << c1.get_count(); cout << “\nc2=” << c2.get_count() ; } class Counter{ int count; public: Counter() : count(0) {} Counter(int c) : count(c) {} int get_count() { return count; } Counter operator ++ (){ ++count; return Counter(count); } }; Postfix Notation • So far we’ve seen the increment operator used only in its prefix form. ++c1 • What about postfix, where the variable is incremented after its value is used in the expression? c1++ class Counter{ private: int count; public: Counter() : count(0) {} Counter(int c) : count(c) {} int get_count() const { return count; } Counter operator ++ (){ return Counter(++count); } Counter operator ++ (int){ return Counter(count++); } }; c1 count 02 31 c2 count main(){ Counter c1, c2; cout << “c1=” << c1.get_count(); cout << “c2=” << c2.get_count(); ++c1; c2 = ++c1; cout << “c1=” << c1.get_count(); cout << “c2=” << c2.get_count(); c2 = c1++; cout << “c1=” << c1.get_count(); cout << “c2=” << c2.get_count() ; } Program Output c1=0 20 ++c1; c2++c1; = c1++; c2=0 c1=2 c1=3 c2=2 c2=2 Example – Distance class • Overload pre-increment and pre-decrement unary operator for distance class such that • • • • Increment: add 1 in feet and 1 in inches Decrement: subtract 1 from feet and 1 from inches Pre increment – prefix Post increment – post fix Overloading Binary Operators • Binary operator can be overloaded as easy as unary operator by using a non static function • Distance objects could be added using a member function add_dist(): dist3.add_dist(dist1, dist2); • By overloading the + operator we can reduce this dense-looking expression to dist3 = dist1 + dist2; class Distance { dist1 d2 private: feet 3 2 feet int feet; inches 2.25 inches 1.5 float inches; dist2 public: feet 2 Distance() : feet(0), inches(0.0) { } Distance(int ft, float in) : feet(ft), inches(in) { } inches 2.25 feet 5 void showdist() const dist3 inches 3.75 { cout << feet << “ : ” << inches ; } feet 5 Distance operator + ( Distance d2) const{ inches 3.75 int f = feet + d2.feet; Distance dist1(3, 4.5); float i = inches + d2.inches; dist4 Distance dist2(11, 6.25); if(i >= 12.0) { feet 10 Distance dist3; i -= 12.0; f++; inches 7.5 dist3 = dist1 + dist2; } return Distance(f,i); Distance dist4; } dist4 =dist3 + dist1 + dist2; }; Cont. • dist3 = dist1 + dist2 • The argument on the left side of the operator (dist1 in this case) is the object of which the operator is a member • The object on the right side of the operator (dist2) is as an argument to the operator + function • The operator returns a object by value, which is assigned to dist3 Overloaded binary operator: one argument Cont. • In the operator+() function, the left operand is accessed directly – since this is the object of which the operator is a member • The right operand is accessed as the function’s argument – as d2.feet and d2.inches • An overloaded operator always requires one less argument than its number of operands, since one operand is the object of which the operator is a member • That’s why unary operators require no arguments Concatenating Strings int main() { char str1[12] = "hello"; char str2[ ] = "world"; strcat(str1, str2); cout << "str1 = " << str1 << endl; cout << "str2 = " << str2 << endl; return 0; } str1[12] he l l o \0 str2[6] wo r l d \0 str1[12] h e l l owo r l d \0 Program Output str1 = helloworld str2 = world • The + operator cannot be used to concatenate C-strings. That is, you can’t say str3 = str1 + str2; • we can overload the + operator to perform such concatenation class String { private: char str[80]; public: String(){ strcpy(str, “"); } String( char s[ ] ) { strcpy(str, s); } void display() const { cout << str; } String operator + (String ss) const { String temp; if( strlen(str) + strlen(ss.str) < 80 ) { strcpy(temp.str, str); strcat(temp.str, ss.str); } else { cout << “\nString overflow”; exit(1); } return temp; } }; String class main() { String s1 = “Hello ”; //String s1("\Hello "); String s2 = “world !”; //String s2(“ world !"); String s3; s1.display(); s2.display(); s3 = s1 + s2; s3.display(); } Program Output Hello world ! Hello world ! Cont. String operator + (String ss) const { String temp; if( strlen(str) + strlen(ss.str) < 80 ) { strcpy(temp.str, str); strcat(temp.str, ss.str); } else { cout << “\nString overflow”; exit(1); } return temp; } ss world! \0 temp Hello \0 World! \0 String s1 = “Hello ”; String s2 = “world !”; String s3; s3 = s1 + s2; s1 Hello \0 s2 world !\0 s3 Hello world!\0 Go to program Overloading -, + and = binary Operators class ThreeD { int x, y, z; public: ThreeD() { x = y = z = 0; } ThreeD(int i, int j, int k) { x = i; y = j; z = k; } ThreeD operator+(ThreeD op2); ThreeD operator=(ThreeD op2); ThreeD operator-(ThreeD op2); void show() ; }; // Overload subtraction. ThreeD ThreeD::operator-(ThreeD op2) { ThreeD temp; temp.x = x - op2.x; temp.y = y - op2.y; temp.z = z - op2.z; return temp; } // Overload +. ThreeD ThreeD::operator+(ThreeD op2) { ThreeD temp; temp.x = x + op2.x; temp.y = y + op2.x; temp.z = z + op2.z; return temp; } Cont. // Overload assignment. ThreeD ThreeD::operator=(ThreeD op2) { x = op2.x; y = op2.y; z = op2.z; return *this; } void ThreeD::show() { cout << x << ", ”<< y << ", ”<< z << "\n"; } PROGRAM OUTPUT: Original value of a: 1, 2, 3 Original value of b: 10, 10, 10 b - a: 9, 8, 7 main() { ThreeD a(1, 2, 3), b(10, 10, 10), c; cout << "Original value of a: "; a.show(); cout << "Original value of b: "; b.show(); c = b - a; cout << “b - a: "; c.show(); } Multiple Overloading • We’ve seen different uses of the + operator: to add distances and to concatenate strings. • You could put both these classes together in the same program, and C++ would still know how to interpret the + operator: • It selects the correct function to carry out the “addition” based on the type of operand • d1 = d2 + d3; • s1 = s2 + s3; Comparison Operator < main() function Distance dist1(3, 4.5); Distance dist2(6, 2.5); if( dist1 < dist2 ) cout << “\ndist1 is less than dist2”; else cout << “\ndist1 is greater than (or equal to) dist2”; bool Distance::operator < (Distance d2) const { float bf1 = feet + inches/12; float bf2 = d2.feet + d2.inches/12; return (bf1 < bf2) ? true : false; } Arithmetic assignment: Operator += main() function Distance dist1(3, 2.5); Distance dist2(5 3.25); dist1 += dist2; void Distance::operator += (Distance d2) { feet += d2.feet; inches += d2.inches; if(inches >= 12.0) { inches -= 12.0; feet++; } } The Subscript Operator [ ] • The subscript operator, [], which is normally used to access array elements, can be overloaded. • This is useful, for example if we want to make a “safe” array: One that automatically checks the index numbers you use to access the array, to ensure that they are not out of bounds. • To be useful, the overloaded subscript operator must return by reference. Cont. • To see why this is true, lets see three example programs that implement a safe array, each one using a different approach to inserting and reading the array elements: • Separate put() and get() functions • A single access() function using return by reference • The overloaded [] operator using return by reference • All programs create a class called safearray, • only member data is an array of 100 int values, • and all three check to ensure that all array accesses are within bounds. Separate get() and put() Functions const int LIMIT = 100; class safearray { private: int arr[LIMIT]; public: void putel(int n, int elvalue) { if( n< 0 || n>=LIMIT ) { cout << “\nIndex out of bounds”; exit(1); } arr[n] = elvalue; } int getel(int n) const { if( n< 0 || n>=LIMIT ){ cout << “\nIndex out of bounds”; exit(1); } return arr[n]; } }; int main() { int temp; safearay sa1; for(int j=0; j<LIMIT; j++) sa1.putel(j, j*10); for(j=0; j<LIMIT; j++) { temp = sa1.getel(j); cout << “Element “ << j << “ is “ << temp ; } } Single access() Function Returning by Reference const int LIMIT = 100; class safearray { private: int arr[LIMIT]; public: int& access(int n) { if( n< 0 || n>=LIMIT ) { cout << “\nIndex out”; exit(1); } return arr[n]; } main() { int temp; safearray sa1; for(int j=0; j<LIMIT; j++) sa1.access(j) = j*10; for(j=0; j<LIMIT; j++) { temp = sa1.access(j); cout << “Element “ << j << “ is “ << temp ; } } The statement sa1.access(j) = j*10; causes the value j*10 to be placed in arr[j], the return value of the function Overloaded [] Operator Returning by Reference main() const int LIMIT = 100; { class safearray { int temp; private: safearray sa1; int arr[LIMIT]; for(int j=0; j<LIMIT; j++) public: sa1[ j ] = j*10; for(j=0; j<LIMIT; j++) { int& operator [ ](int n) { temp = sa1[ j ]; if( n< 0 || n>=LIMIT ) { cout << “Element “ << j cout << “\nIndex out of bounds”; << “ is “ << temp ; exit(1); } } } return arr[n]; } } Overloading Restrictions • Can not overload the operators as they apply to builit-in data types. Example: y = 5; x = y + 5; // overloading + operator so that x becomes 15 is illegal. • Must respect the original "Functional" template of the operators. You can not convert a unary operator to a binary operator. Example: y = x ++ z; //Illegal • You can not change the operator's precedence. Example: Can not make the + operator higher precedence than the * operator. Not All Operators Can Be Overloaded • The following operators cannot be overloaded • • • • • member access or dot operator (.) scope resolution operator (::) the conditional operator (?:) pointer-to-member operator (->) can’t create new operators (like *&) and try to overload them • only existing operators can be overloaded. Data Conversion • The = operator will assign a value from one variable to another, instatements like intvar1 = intvar2; where intvar1 and intvar2 are integer variables • Also, = assigns the value of one user-defined object to another, provided they are of the same type, in statements like dist3 = dist1 + dist2; where the result of the addition, is assigned to another object of type Distance, dist3. • dist4 = dist3; Cont. • Thus, assignments between types, whether they are basic types or user-defined types, are handled by the compiler with no effort on our part, provided that the same data type is used on both sides of the equal sign • what happens when the variables on different sides of the = are of different types? • For example: • dist2 = 7.55; Distance class class Distance { private: int feet; float inches; public: Distance() : feet(0), inches(0.0) {} Distance(int ft, float in) : feet(ft), inches(in) {} void getdist() { cout << “\nEnter feet: “; cin >> feet; cout << “Enter inches: “; cin >> inches; } void showdist() const { cout << feet << “ : ” << inches ; } }; Conversions Between Objects and Basic Types main() { Distance(float meters) { float mtrs; float fltfeet = 3.280833 * meters; Distance dist1 = 2.35; feet = int(fltfeet); cout << “dist1=“; inches = 12*(fltfeet-feet); dist1.showdist(); } mtrs = dist1; operator float() const { cout << “\ndist1 = “ << mtrs << “ float fracfeet = inches/12; meters\n”; fracfeet += feet; Distance dist2(5, 10.25); return fracfeet/3.280833; mtrs = dist2; } cout << “\ndist2 = “ << mtrs << “ PROGRAM OUTOUT meters\n”; dist1 = 7 : 8.51949 } dist1 = 2.35 meters dist2 = 1.78435 meters Conversions Between Objects of Different Classes • Can be done using • one-argument constructor • 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; Cont. • In the above statement, object_B of type B is converted to type A and assigned toobject_A. • object_B is the source and object_A is the destination. • 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. Example program 01: km to miles class Kilometers{ private: double kms; public: Kilometers(double k) : kms(k) { } void display() { cout<<kms; } double getValue() { return kms; } }; class Miles { private: double miles; public: Miles(double m) : miles(m) { } Miles(Kilometers KM) { miles = KM.getValue()/1.61; } void display() { cout <<“ miles = “<< miles; } operator Kilometers() { return Kilometers(miles*1.61); } }; Cont. main( ) { // 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; k2.display(); cout << " = "; m2.display(); cout << endl; Output 100 miles = 160.934 kilometeres 100 kilometers = 62.1371 miles • Any Questions Contact information: Engr. Muhammad Salman Saeed Academic Block 3rd Floor, CS-19 salman.saeed@giki.edu.pk