1 1 Video Lecture
Introduction  Operator Overloading is one of the most exciting features of object oriented programming.  It can transform complex, obscure program listings into intuitively obvious ones. For example,  Statements like d3.addobjects(d1, d2); or the similar but equally obscure d3 = d1.addobjects(d2); can be changed to the much more readable d3 = d1 + d2;  The rather forbidding term operator overloading refers to giving the normal C++ operators, such as +, *, <=, and +=, additional meanings when they are applied to user defined data types. 2
Introduction  Let’s start off by overloading a unary operator.  Unary operators act on only one operand. (An operand is simply a variable acted on by an operator.)  Examples are the increment and decrement operators ++ and --, and the unary minus, as in -33.  In Chapter 6, we created a class Counter to keep track of a count. Objects of that class were incremented by calling a member function: c1.inc_count();  That did the job, but the listing would have been more readable if we could have used the increment operator ++ instead: ++c1; 3
Example 1: Overloading Unary (++) Operator // increment variable with ++ operator #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // count public: Counter() : count(0){ // constructor } int return_count(){ // return count return count; } // increment (prefix operator overloading) void operator ++ () { ++count; } }; int main() { Counter c1, c2; // define and initialize cout << "nc1=" << c1.return_count(); cout << "nc2=" << c2.return_count(); ++c1; // increment c1 ++c2; // increment c2 ++c2; // increment c2 cout << "nc1=" << c1.return_count(); cout << "nc2=" << c2.return_count() << endl; system("PAUSE"); return 0; } 4
The operator Keyword  The keyword operator is used to overload the ++ operator in this declarator: void operator ++ ()  The return type (void in this case) comes first, followed by the keyword operator, followed by the operator itself (++), and finally the argument list enclosed in parentheses (which are empty here).  This declarator syntax tells the compiler to call this member function whenever the ++ operator is encountered, provided the operand (the variable operated on by the ++) is of type Counter. If the operand is a basic type such as an int, as in ++intvar; then the compiler will use its built-in routine to increment an int. 5
operator Arguments  In main() the ++ operator is applied to a specific object, as in the expression ++c1.  The operator ++() takes no arguments.  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. 6
operator Return Values  The operator ++() function in the program has a subtle defect. You will discover it if you use a statement like this in main(): c1 = ++c2;  The compiler will complain. Because we have defined the ++ operator 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.  To make it possible to use our homemade operator ++() in assignment expressions, we must provide a way for it to return a value.  The next program does that. 7
Example 2: Returning Values in Operator (1/2) #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // define count attribute public: Counter() : count(0) { // make no argument constructor } int get_count() { // return value of count return count; } Counter operator ++ () { // increment count ++count; // increment count Counter temp; // make a temporary Counter temp.count = count; // give it same value as this object return temp; // return the copy } }; 8
Example 2: Returning Values in Operator (2/2) int main() { Counter c1, c2; // c1=0, c2=0 cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); ++c1; // c1=1 c2 = ++c1; // c1=2, c2=2 cout << "nc1=" << c1.get_count(); // display again cout << "nc2=" << c2.get_count() << endl; system("PAUSE"); return 0; } 9
Example 3: Returning Nameless Temporary Objects (1/2) // increment with ++ operator uses unnamed temporary object #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // define count attribute public: Counter() : count(0) { // make no argument constructor } Counter(int c) : count(c) { // make one argument constructor } int get_count() { // return value of count return count; } Counter operator ++ () { // increment count ++count; // increment count, then return return Counter(count); // an unnamed temporary object } // initialized to this count }; 10
Example 3: Returning Nameless Temporary Objects (2/2) int main() { Counter c1, c2; // c1=0, c2=0 cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); ++c1; // c1=1 c2 = ++c1; // c1=2, c2=2 cout << "nc1=" << c1.get_count(); // display again cout << "nc2=" << c2.get_count() << endl; system("PAUSE"); return 0; } 11
Example 4: Using Postfix Notation (1/2) // overloaded ++ operator in both prefix and postfix #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // define count attribute public: Counter() : count(0) {} // make no argument constructor Counter(int c) : count(c) {} // make one argument constructor int get_count() const { // return value of count return count; } Counter operator ++ () { // increment count (prefix version) return Counter(++count); // increment count, then } // return an unnamed temporary object Counter operator ++ (int) { // increment count (postfix) return Counter(count++); // object initialized to this } // count, then increment count }; 12
Example 4: Using Postfix Notation (2/2) int main() { Counter c1, c2; // c1=0, c2=0 cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); ++c1; // c1=1 c2 = ++c1; // c1=2, c2=2 (prefix) cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); c2 = c1++; // c1=3, c2=2 (postfix) cout << "nc1=" << c1.get_count(); // display again cout << "nc2=" << c2.get_count() << endl; system("PAUSE"); return 0; } 13 Similarly you can do operator overloading of following operators Operator Example -- c1 = --c2; -- c1 = c2--; - c1 = -c2; ! c1 = !c2; ~ c1 = ~c2;
Using Postfix Notation  In the program, We have two different declarations for overloading the ++ operator.  Declaration for prefix notation is Counter operator ++ ()  for postfix notation, is Counter operator ++ (int)  The only difference is the int in the parentheses.  This int isn’t really an argument, and it doesn’t mean integer.  It’s simply a signal to the compiler to create the postfix version of the operator. 14
Example 5: Overloading Binary Operators (1/3) // englplus.cpp overloaded ‘+’ operator adds two Distances #include <iostream> #include <stdlib.h> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) {} // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } Distance operator + (Distance) const; // add 2 distances }; 15
Example 5: Overloading Binary Operators (2/3) Distance Distance::operator + (Distance d2) const { // add this distance to d2 and return sum int f = feet + d2.feet; // add the feet float i = inches + d2.inches; // add the inches if (i >= 12.0) { // if total exceeds 12.0, i -= 12.0; // then decrease inches by 12.0 and f++; // increase feet by 1 } // return a temporary Distance return Distance(f, i); // initialized to sum } int main() { Distance dist1, dist3, dist4; // define distances dist1.getdist(); // get dist1 from user Distance dist2(11, 6.25); // define, initialize dist2 dist3 = dist1 + dist2; // single ‘+’ operator dist4 = dist1 + dist2 + dist3; // multiple ‘+’ operators cout << "dist1 = "; dist1.showdist(); cout << endl; cout << "dist2 = "; dist2.showdist(); cout << endl; cout << "dist3 = "; dist3.showdist(); cout << endl; cout << "dist4 = "; dist4.showdist(); cout << endl; system("PAUSE"); return 0; } 16
Overloading Binary Operators  Binary operators ( +, -, *, /, %, =, +=, -=, *=, /=, %=) can be overloaded just as easily as unary operators.  In class Distance the declaration for the operator+() function looks like this: Distance operator + ( Distance );  This function has a return type of Distance, and takes one argument of type Distance.  In expressions like 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) must be furnished as an argument to the operator.  The operator returns a value, which can be assigned or used in other ways; in this case it is assigned to dist3. 17
Overloading Binary Operators 18
Example 6: Concatenating String (1/3) // strplus.cpp overloaded ‘+’ operator concatenates strings #include <iostream> #include <string.h> // for strcpy_s(), strcat() #include <stdlib.h> // for exit() using namespace std; class String { // user-defined string type private: enum { SZ = 80 }; // we use enum for integer constants char str[SZ]; // size of String objects holds a string public: String() { // no argument constructor strcpy_s(str, ""); } String(const char s[]) { // one argument constructor strcpy_s(str, s); } void display() const { // display the String cout << str; } 19
Example 6: Concatenating String (2/3) String operator + (String ss) const { // add Strings String temp; // make a temporary String if (strlen(str) + strlen(ss.str) < SZ) { strcpy_s(temp.str, str); // copy this string to temp strcat_s(temp.str, ss.str); // add the argument string } else { cout << "n String overflow"; exit(1); } return temp; // return temp String } }; 20
Example 6: Concatenating String (3/3) int main() { String s1 = "nEid Mubarak! "; // uses one arg. constructor String s2 = "Happy new year!"; // uses one arg. constructor String s3; // uses no arg. constructor s1.display(); cout << endl; // display strings s2.display(); cout << endl; s3.display(); cout << endl; s3 = s1 + s2; // add s2 to s1, then assign it to s3 s3.display(); // display s3 cout << endl; system("PAUSE"); return 0; } 21
Enumeration  An enumeration, introduced by the keyword enum and followed by a type name (in our example, Status), is a set of integer constants represented by identifiers.  The values of these enumeration constants start at 0, unless specified otherwise, and increment by 1.  In the following example, the constant CONTINUE has the value 0, WON has the value 1 and LOST has the value 2. enum Status { CONTINUE, WON, LOST };  Another popular enumeration is enum Months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }; 22
Concatenating String  The + operator cannot be used to concatenate C-strings. That is, you can’t say str3 = str1 + str2;  The program first displays three strings separately.  The third is empty at this point, so nothing is printed when it displays itself.  Then the first two strings are concatenated and placed in the third, and the third string is displayed again.  The declarator String operator + (String ss) shows that the + operator takes one argument of type String and returns an object of the same type.  The concatenation process in operator+() involves creating a temporary object of type String, copying the string from our own String object into it, concatenating the argument string using the library function strcat(), and returning the resulting temporary string. 23
Concatenating String  Note that we can’t use the return String(string); approach, where a nameless temporary String is created,  because we need access to the temporary String not only to initialize it, but to concatenate the argument string to it.  We must be careful that we don’t overflow the fixed-length strings used in the String class. To prevent such accidents in the operator+() function, we check that the combined length of the two strings to be concatenated will not exceed the maximum string length.  We’ve seen different uses of the + operator: to add English 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. 24
Example 7: Overloading Comparison (<) Operator (1/2) // overloaded '<' operator compares two Distances #include <iostream> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) { } // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } bool operator < (Distance) const; // compare distances }; 25
Example 7: Overloading Comparison (<) Operator (2/2) bool Distance::operator < (Distance d2) const { float bf1 = feet + inches / 12; float bf2 = d2.feet + d2.inches / 12; return bf1 < bf2; } int main() { Distance dist1; // define Distance dist1 dist1.getdist(); // get dist1 from user Distance dist2(6, 2.5); // define and initialize dist2 cout << "ndist1 = "; dist1.showdist(); // display distances cout << "ndist2 = "; dist2.showdist(); if (dist1 < dist2) // overloaded '<' operator cout << "ndist1 is less than dist2"; else cout << "ndist1 is greater than (or equal to) dist2"; cout << endl; system("PAUSE"); return 0; } 26
Overloading Comparison (<) Operator  The approach used in the operator < () function is similar to overloading the + operator, except that here the operator < () function has a return type of bool.  The return value is false or true, depending on the comparison of the two distances.  The comparison is made by converting both distances to floating-point feet, and comparing them using the normal < operator.  Remember that the use of the conditional operator return (bf1 < bf2) ? true : false; is the same as if(bf1 < bf2) return true; else return false; 27
Example 8: Overloading Comparison (==) Operator (1/2) // overloaded '==' operator compares strings #include <iostream> #include <string.h> // for strcmp() using namespace std; class String { // user-defined string type private: enum { SZ = 80 }; // size of String objects char str[SZ]; // holds a string public: String() { // constructor, no args strcpy_s(str, ""); } String(const char *s) { // constructor, one arg strcpy_s(str, s); } void display() const { // display a String cout << str; } 28
Example 8: Overloading Comparison (==) Operator (2/2) void getstr() { // read a string cin.get(str, SZ); } bool operator == (String ss) const { // check for equality return !strcmp(str, ss.str); } }; int main() { String s1 = "yes", s2 = "no", s3; cout << "nEnter 'yes' or 'no': "; s3.getstr(); // get String from user if (s3 == s1) cout << "You typed yesn"; // compare with "yes" else if (s3 == s2) cout << "You typed non"; // compare with "no" else cout << "You didn’t follow instructionsn"; system("PAUSE"); return 0; } 29
Example 9: Overloading Comparison (+=) Operator (1/2) // englpleq.cpp overloaded '+=' assignment operator #include <iostream> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) { } // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } void operator += (Distance); }; 30
Example 9: Overloading Comparison (+=) Operator (2/2) void Distance::operator += (Distance d2) { // add distance to this one feet += d2.feet; // add the feet inches += d2.inches; // add the inches if (inches >= 12.0) { // if total exceeds 12.0, inches -= 12.0; // then decrease inches by 12.0 feet++; // and increase feet by 1 } } int main() { Distance dist1; // define dist1 dist1.getdist(); // get dist1 from user cout << "ndist1 = "; dist1.showdist(); Distance dist2(11, 6.25); // define, initialize dist2 cout << "ndist2 = "; dist2.showdist(); dist1 += dist2; // dist1 = dist1 + dist2 cout << "nAfter addition,"; cout << "ndist1 = "; dist1.showdist(); cout << endl; system("PAUSE"); return 0; } 31
Arithmetic Assignment (+=) Operators  In the operator +=() function in program, the object that takes on the value of the sum is the object of which the function is a member.  Thus it is feet and inches that are given values, not temporary variables used only to return an object. The operator+=() function has no return value; it returns type void.  A return value is not necessary with arithmetic assignment operators such as +=, because the result of the assignment operator is not assigned to anything.  The operator is used alone, in expressions like the one in the program. dist1 += dist2;  If you wanted to use this operator in more complex expressions, like dist3 = dist1 += dist2;  then you would need to provide a return value (i.e. a distance object). 32
Example 10: Separate getel() and putel() Functions (1/2) // creates safe array uses separate put and get functions #include <iostream> #include <process.h> // for exit() using namespace std; const int LIMIT = 100; class safearay { private: int arr[LIMIT]; public: void putel(int n, int elvalue) { // set value of element if (n < 0 || n >= LIMIT) { cout << "nIndex out of bounds"; system("PAUSE"); exit(1); } arr[n] = elvalue; } 33
Example 10: Separate getel() and putel() Functions (2/2) int getel(int n) const { // get value of element if (n < 0 || n >= LIMIT) { cout << "nIndex out of bounds"; system("PAUSE"); exit(1); } return arr[n]; } }; int main() { safearay sa1; for (int j = 0; j < LIMIT; j++) // insert elements sa1.putel(j, j * 10); for (int j = 0; j < LIMIT; j++) { // display elements int temp = sa1.getel(j); cout << "Element " << j << " is " << temp << endl; } system("PAUSE"); return 0; } 34
Ex 11: Single access() Function Returning by Reference (1/2) // uses one access() function for both put and get #include <iostream> #include <process.h> // for exit() using namespace std; const int LIMIT = 100; // array size class safearay { private: int arr[LIMIT]; public: int& access(int n) { if (n < 0 || n >= LIMIT) { cout << "n Index out of bounds"; system("PAUSE"); exit(1); } return arr[n]; } }; 35
Ex 11: Single access() Function Returning by Reference (2/2) int main() { safearay sa1; for (int j = 0; j < LIMIT; j++) // insert elements sa1.access(j) = j * 10; // *left* side of equal sign for (int j = 0; j < LIMIT; j++) { // display elements int temp = sa1.access(j); //*right* side of equal sign cout << "Element " << j << " is " << temp << endl; } system("PAUSE"); return 0; } 36
Ex 12: Overloaded [] Operator Returning by Reference (1/2) // creates safe array, uses overloaded [] operator for both put and get #include <iostream> #include <process.h> // for exit() const int LIMIT = 100; // array size using namespace std; class safearay { private: int arr[LIMIT]; public: int& operator [](int n) { if (n < 0 || n >= LIMIT) { cout << "n Index out of bounds"; exit(1); } return arr[n]; } }; 37
Ex 12: Overloaded [] Operator Returning by Reference (2/2) int main() { safearay sa1; for (int j = 0; j < LIMIT; j++) // insert elements sa1[j] = j * 10; // *left* side of equal sign for (int j = 0; j < LIMIT; j++) // display elements { int temp = sa1[j]; // *right* side of equal sign cout << "Element " << j << " is " << temp << endl; } system("PAUSE"); return 0; } 38
Ex 13: Conversion Between Objects and Basic Types (1/3) // conversions: Distance to meters, meters to Distance #include <iostream> using namespace std; class Distance { // English Distance class private: const float MTF; // meters to feet int feet; float inches; public: Distance() : feet(0), inches(0.0), MTF(3.280833F) { } // constructor (one arg) Distance(float meters) : MTF(3.280833F) { // convert meters to Distance float fltfeet = MTF * meters; // convert to float feet feet = int(fltfeet); // feet is integer part inches = 12 * (fltfeet - feet); // inches is what’s left } 39
Ex 13: Conversion Between Objects and Basic Types (2/3) Distance(int ft, float in) : feet(ft), inches(in), MTF(3.280833F) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } operator float() const // conversion operator { // converts Distance to meters float fracfeet = inches / 12; // convert the inches fracfeet += static_cast<float>(feet); //add the feet return fracfeet / MTF; // convert to meters } }; 40
Ex 13: Conversion Between Objects and Basic Types (3/3) int main() { float mtrs; Distance dist1 = 2.35F; // uses 1-arg constructor to convert meters to Distance cout << "ndist1 = "; dist1.showdist(); mtrs = static_cast<float>(dist1); // uses conversion operator cout << "ndist1 = " << mtrs << " metersn"; // for Distance to meters Distance dist2(5, 10.25); // uses 2-arg constructor mtrs = dist2; // also uses conversion op cout << "ndist2 = " << mtrs << " metersn"; // dist2 = mtrs; // error, = won’t convert system("PAUSE"); return 0; } 41
Ex 14: Conversion Between C-String and String Objects (1/2) // conversion between ordinary strings and class String #include <iostream> #include <string.h> // for strcpy_s(), etc. using namespace std; class String { // user-defined string type private: enum { SZ = 80 }; // size of all String objects char str[SZ]; // holds a C-string public: String() { str[0] = '0'; } // no-arg constructor String(const char s[]) { // 1-arg constructor converts C-string to String Object strcpy_s(str, s); } void display() const { // display the String cout << str << endl; } operator char* () { // conversion operator converts String to C-string return str; } }; 42
Ex 14: Conversion Between C-String and String Objects (2/2) int main() { String s1; // uses no-arg constructor char xstr[] = "Hello World "; // create and initialize C-string s1 = xstr; // uses 1-arg constructor to convert C-string to String Object s1.display(); // display String String s2 = "Good Morning "; // uses 1-arg constructor to initialize String cout << static_cast<char*>(s2); // use conversion operator to convert String to C-string // before sending to << op cout << endl; system("PAUSE"); return 0; } 43
Ex 15: Conversions Between Objects of Different Classes (1/3) // converts from Polar Coordinates to Cartesian Coordinates // using 1-Arg constructor in the Cartesian Class #define M_PI 3.14159265358979323846 // value of pi #include <math.h> #include <iostream> #include <string> using namespace std; class Polar { // for 2D Polar Coordinates public: double R; // Radius double Theta; // Theta in Degrees Polar() : R(0), Theta(0) { } Polar(double R, double Theta) : R(R), Theta(Theta) { } void Show() const { cout << "R = " << R << ", Theta = " << Theta << " Degrees" << endl; } }; 44 X Y r θ y x P(x,y) Cartesian P(r,θ) Polar
Ex 15: Conversions Between Objects of Different Classes (2/3) class Cartesian { // for 2D Cartesian Coordinates public: double X, Y; Cartesian() : X(0), Y(0) { } Cartesian(double X, double Y) : X(X), Y(Y) { } Cartesian(Polar P) { double r, t; r = P.R; // Get Radius t = P.Theta; // Get Theta t *= M_PI / 180; // Convert Degrees to Radians X = r * cos(t); // Calculate X Y = r * sin(t); // Calculate Y } void Show() const { cout << "X = " << X << ", Y = " << Y << endl; } }; 45 X Y r θ y x P(x,y) Cartesian P(r,θ) Polar
Ex 15: Conversions Between Objects of Different Classes (3/3) int main() { Polar Pol(5, 53.13); // R = 5, Theta = 53.13 Degrees Cartesian Cat = Pol; // Convert Polar to Cartesian Pol.Show(); // Show in Polar Cat.Show(); // Show in Cartesian system("PAUSE"); return 0; } 46
Ex 16: Conversions Between Objects of Different Classes (1/3) // converts from Polar Coordinates to Cartesian Coordinates using Operator Overloading in // Polar Class #define M_PI 3.14159265358979323846 //pi #include <math.h> #include <iostream> #include <string> using namespace std; class Cartesian // A Class for 2D Cartesian Coordinates { public: double X, Y; Cartesian() : X(0), Y(0) { } Cartesian(double X, double Y) : X(X), Y(Y) { } void Show() const { cout << "X = " << X << ", Y = " << Y << endl; } }; 47
Ex 16: Conversions Between Objects of Different Classes (2/3) class Polar { // for 2D Polar Coordinates public: double R; // Radius double Theta; // Theta in Degrees public: Polar() : R(0), Theta(0) { } Polar(double R, double Theta) : R(R), Theta(Theta) { } void Show() const { cout << "R = " << R << ", Theta = " << Theta << " Degrees" << endl; } operator Cartesian() const { double x, y, t; t = Theta * M_PI / 180; // Converts Degrees to Radians x = R * cos(t); y = R * sin(t); return Cartesian(x, y); } }; 48 X Y r θ y x P(x,y) Cartesian P(r,θ) Polar
Ex 16: Conversions Between Objects of Different Classes (3/3) int main() { Polar Pol(5, 53.13); // R = 5, Theta = 53.13 Degrees Cartesian Cat = Pol; // Convert Polar to Cartesian Pol.Show();// Show in Polar Cat.Show();// Show in Cartesian system("PAUSE"); return 0; } 49
Preventing Conversions with explicit  You can call fancyDist() with arguments Distance variable is no problem.  you can also call fancyDist() with a variable of type float as the argument: fancyDist(mtrs);  The compiler will realize it’s the wrong type and look for a conversion operator.  Finding a Distance constructor that takes type float as an argument, it will arrange for this constructor to convert float to Distance and pass the Distance value to the function.  This is an implicit conversion, one which you may not have intended to make possible.  However, if we make the constructor explicit, we prevent implicit conversions.  You can check this by removing the comment symbol from the call to fancyDist() in the program: 50
Preventing Conversions with explicit  The compiler will tell you it can’t perform the conversion. Without the explicit keyword, this call is perfectly legal.  As a side effect of the explicit constructor, note that you can’t use the form of object initialization that uses an equal sign Distance dist1 = 2.35F;  Whereas the form with parentheses works as it always has: Distance dist1(2.35F);  Ordinarily, when you create a const object, you want a guarantee that none of its member data can be changed. However, a situation occasionally arises where you want to create const objects that have some specific member data item that needs to be modified despite the object’s constness.  Let’s say we want to be able to create const scrollbars in which attributes remain unchanged, except for their ownership. That’s where the mutable keyword comes in. 51
Ex 17: Preventing Conversions with explicit (1/2) #include <iostream> using namespace std; class Distance { private: const float MTF; //meters to feet int feet; float inches; public: //no-args constructor Distance() : feet(0), inches(0.0), MTF(3.280833F) { } // EXPLICIT one-arg constructor explicit Distance(float meters) : MTF(3.280833F) { float fltfeet = MTF * meters; feet = int(fltfeet); inches = 12*(fltfeet-feet); } void showdist(){ cout << feet << "'-" << inches << '"'; } }; 52
Ex 17: Preventing Conversions with explicit (2/2) int main(){ void fancyDist(Distance); //declaration Distance dist1(2.35F); //uses 1-arg constructor to convert meters to Distance // Distance dist1 = 2.35F; // ERROR if constructor is explicit cout << "ndist1 = "; dist1.showdist(); float mtrs = 3.0F; // fancyDist(mtrs); // ERROR if constructor is explicit return 0; } void fancyDist(Distance d) { cout << "(in feet and inches) = "; d.showdist(); cout << endl; } 53
Ex 18: Changing const Object Data Using mutable (1/2) #include <iostream> #include <string> using namespace std; class scrollbar { private: int size; // related to constness mutable string owner; // not relevant to constness public: scrollbar(int sz, string own) : size(sz), owner(own){ } void setSize(int sz) : size(sz) { } // changes size void setOwner(string own) const { // changes owner owner = own; } int getSize() const { // returns size return size; } string getOwner() const { // returns owner return owner; } }; 54
Ex 18: Changing const Object Data Using mutable (1/2) int main() { const scrollbar sbar(60, "Window1"); // sbar.setSize(100); // can’t do this to const obj sbar.setOwner("Window2"); // this is OK // these are OK too cout << sbar.getSize() << ", " << sbar.getOwner() << endl; system("PAUSE"); return 0; } 55
Ex 19: stream insertion (<<) & extraction (>>) operator (1/2) // stream insertion (<<) and stream extraction (>>) operator #include <iostream> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) { } // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in){ } friend istream& operator >> (istream& input , Distance& dist); friend ostream& operator << (ostream& output, const Distance& dist); }; // overloading of stream extraction operator istream& operator >> (istream& input, Distance& dist) { cout << "Enter Feet: "; input >> dist.feet; cout << "Enter Inches: "; input >> dist.inches; return input; } 56
Ex 19: stream insertion (<<) & extraction (>>) operator (2/2) // overloading of stream insertion operator ostream& operator << (ostream& output, const Distance& dist) { output << dist.feet << "'-"<< dist.inches << '"'; return output; } int main() { Distance dist1; // define Distance dist1 cin >> dist1; // now calling stream extraction operator >> cout << "You Entered: " << dist1 << endl; // now calling stream insertion operator << system("PAUSE"); return 0; } 57
Summary 58 These operators can be overloaded in C++ ++ -- ! ~ - + * / % ^ & && | || < << > >> != ~= += -= *= /= %= ^= &= &&= |= ||= <= <<= >= >>= == [] = -> ->* () , new delete new[ ] delete[ ] These operators cannot be overloaded in C++ . .* :: ?: sizeof
Assignment # 2 59 Assignment No.2.doc Assignment No.2.pdf

Object Oriented Programming using C++: Ch08 Operator Overloading.pptx

  • 1.
  • 2.
    Introduction  Operator Overloadingis one of the most exciting features of object oriented programming.  It can transform complex, obscure program listings into intuitively obvious ones. For example,  Statements like d3.addobjects(d1, d2); or the similar but equally obscure d3 = d1.addobjects(d2); can be changed to the much more readable d3 = d1 + d2;  The rather forbidding term operator overloading refers to giving the normal C++ operators, such as +, *, <=, and +=, additional meanings when they are applied to user defined data types. 2
  • 3.
    Introduction  Let’s startoff by overloading a unary operator.  Unary operators act on only one operand. (An operand is simply a variable acted on by an operator.)  Examples are the increment and decrement operators ++ and --, and the unary minus, as in -33.  In Chapter 6, we created a class Counter to keep track of a count. Objects of that class were incremented by calling a member function: c1.inc_count();  That did the job, but the listing would have been more readable if we could have used the increment operator ++ instead: ++c1; 3
  • 4.
    Example 1: OverloadingUnary (++) Operator // increment variable with ++ operator #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // count public: Counter() : count(0){ // constructor } int return_count(){ // return count return count; } // increment (prefix operator overloading) void operator ++ () { ++count; } }; int main() { Counter c1, c2; // define and initialize cout << "nc1=" << c1.return_count(); cout << "nc2=" << c2.return_count(); ++c1; // increment c1 ++c2; // increment c2 ++c2; // increment c2 cout << "nc1=" << c1.return_count(); cout << "nc2=" << c2.return_count() << endl; system("PAUSE"); return 0; } 4
  • 5.
    The operator Keyword The keyword operator is used to overload the ++ operator in this declarator: void operator ++ ()  The return type (void in this case) comes first, followed by the keyword operator, followed by the operator itself (++), and finally the argument list enclosed in parentheses (which are empty here).  This declarator syntax tells the compiler to call this member function whenever the ++ operator is encountered, provided the operand (the variable operated on by the ++) is of type Counter. If the operand is a basic type such as an int, as in ++intvar; then the compiler will use its built-in routine to increment an int. 5
  • 6.
    operator Arguments  Inmain() the ++ operator is applied to a specific object, as in the expression ++c1.  The operator ++() takes no arguments.  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. 6
  • 7.
    operator Return Values The operator ++() function in the program has a subtle defect. You will discover it if you use a statement like this in main(): c1 = ++c2;  The compiler will complain. Because we have defined the ++ operator 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.  To make it possible to use our homemade operator ++() in assignment expressions, we must provide a way for it to return a value.  The next program does that. 7
  • 8.
    Example 2: ReturningValues in Operator (1/2) #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // define count attribute public: Counter() : count(0) { // make no argument constructor } int get_count() { // return value of count return count; } Counter operator ++ () { // increment count ++count; // increment count Counter temp; // make a temporary Counter temp.count = count; // give it same value as this object return temp; // return the copy } }; 8
  • 9.
    Example 2: ReturningValues in Operator (2/2) int main() { Counter c1, c2; // c1=0, c2=0 cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); ++c1; // c1=1 c2 = ++c1; // c1=2, c2=2 cout << "nc1=" << c1.get_count(); // display again cout << "nc2=" << c2.get_count() << endl; system("PAUSE"); return 0; } 9
  • 10.
    Example 3: ReturningNameless Temporary Objects (1/2) // increment with ++ operator uses unnamed temporary object #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // define count attribute public: Counter() : count(0) { // make no argument constructor } Counter(int c) : count(c) { // make one argument constructor } int get_count() { // return value of count return count; } Counter operator ++ () { // increment count ++count; // increment count, then return return Counter(count); // an unnamed temporary object } // initialized to this count }; 10
  • 11.
    Example 3: ReturningNameless Temporary Objects (2/2) int main() { Counter c1, c2; // c1=0, c2=0 cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); ++c1; // c1=1 c2 = ++c1; // c1=2, c2=2 cout << "nc1=" << c1.get_count(); // display again cout << "nc2=" << c2.get_count() << endl; system("PAUSE"); return 0; } 11
  • 12.
    Example 4: UsingPostfix Notation (1/2) // overloaded ++ operator in both prefix and postfix #include <iostream> #include <stdlib.h> using namespace std; class Counter { private: int count; // define count attribute public: Counter() : count(0) {} // make no argument constructor Counter(int c) : count(c) {} // make one argument constructor int get_count() const { // return value of count return count; } Counter operator ++ () { // increment count (prefix version) return Counter(++count); // increment count, then } // return an unnamed temporary object Counter operator ++ (int) { // increment count (postfix) return Counter(count++); // object initialized to this } // count, then increment count }; 12
  • 13.
    Example 4: UsingPostfix Notation (2/2) int main() { Counter c1, c2; // c1=0, c2=0 cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); ++c1; // c1=1 c2 = ++c1; // c1=2, c2=2 (prefix) cout << "nc1=" << c1.get_count(); // display cout << "nc2=" << c2.get_count(); c2 = c1++; // c1=3, c2=2 (postfix) cout << "nc1=" << c1.get_count(); // display again cout << "nc2=" << c2.get_count() << endl; system("PAUSE"); return 0; } 13 Similarly you can do operator overloading of following operators Operator Example -- c1 = --c2; -- c1 = c2--; - c1 = -c2; ! c1 = !c2; ~ c1 = ~c2;
  • 14.
    Using Postfix Notation In the program, We have two different declarations for overloading the ++ operator.  Declaration for prefix notation is Counter operator ++ ()  for postfix notation, is Counter operator ++ (int)  The only difference is the int in the parentheses.  This int isn’t really an argument, and it doesn’t mean integer.  It’s simply a signal to the compiler to create the postfix version of the operator. 14
  • 15.
    Example 5: OverloadingBinary Operators (1/3) // englplus.cpp overloaded ‘+’ operator adds two Distances #include <iostream> #include <stdlib.h> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) {} // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } Distance operator + (Distance) const; // add 2 distances }; 15
  • 16.
    Example 5: OverloadingBinary Operators (2/3) Distance Distance::operator + (Distance d2) const { // add this distance to d2 and return sum int f = feet + d2.feet; // add the feet float i = inches + d2.inches; // add the inches if (i >= 12.0) { // if total exceeds 12.0, i -= 12.0; // then decrease inches by 12.0 and f++; // increase feet by 1 } // return a temporary Distance return Distance(f, i); // initialized to sum } int main() { Distance dist1, dist3, dist4; // define distances dist1.getdist(); // get dist1 from user Distance dist2(11, 6.25); // define, initialize dist2 dist3 = dist1 + dist2; // single ‘+’ operator dist4 = dist1 + dist2 + dist3; // multiple ‘+’ operators cout << "dist1 = "; dist1.showdist(); cout << endl; cout << "dist2 = "; dist2.showdist(); cout << endl; cout << "dist3 = "; dist3.showdist(); cout << endl; cout << "dist4 = "; dist4.showdist(); cout << endl; system("PAUSE"); return 0; } 16
  • 17.
    Overloading Binary Operators Binary operators ( +, -, *, /, %, =, +=, -=, *=, /=, %=) can be overloaded just as easily as unary operators.  In class Distance the declaration for the operator+() function looks like this: Distance operator + ( Distance );  This function has a return type of Distance, and takes one argument of type Distance.  In expressions like 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) must be furnished as an argument to the operator.  The operator returns a value, which can be assigned or used in other ways; in this case it is assigned to dist3. 17
  • 18.
  • 19.
    Example 6: ConcatenatingString (1/3) // strplus.cpp overloaded ‘+’ operator concatenates strings #include <iostream> #include <string.h> // for strcpy_s(), strcat() #include <stdlib.h> // for exit() using namespace std; class String { // user-defined string type private: enum { SZ = 80 }; // we use enum for integer constants char str[SZ]; // size of String objects holds a string public: String() { // no argument constructor strcpy_s(str, ""); } String(const char s[]) { // one argument constructor strcpy_s(str, s); } void display() const { // display the String cout << str; } 19
  • 20.
    Example 6: ConcatenatingString (2/3) String operator + (String ss) const { // add Strings String temp; // make a temporary String if (strlen(str) + strlen(ss.str) < SZ) { strcpy_s(temp.str, str); // copy this string to temp strcat_s(temp.str, ss.str); // add the argument string } else { cout << "n String overflow"; exit(1); } return temp; // return temp String } }; 20
  • 21.
    Example 6: ConcatenatingString (3/3) int main() { String s1 = "nEid Mubarak! "; // uses one arg. constructor String s2 = "Happy new year!"; // uses one arg. constructor String s3; // uses no arg. constructor s1.display(); cout << endl; // display strings s2.display(); cout << endl; s3.display(); cout << endl; s3 = s1 + s2; // add s2 to s1, then assign it to s3 s3.display(); // display s3 cout << endl; system("PAUSE"); return 0; } 21
  • 22.
    Enumeration  An enumeration,introduced by the keyword enum and followed by a type name (in our example, Status), is a set of integer constants represented by identifiers.  The values of these enumeration constants start at 0, unless specified otherwise, and increment by 1.  In the following example, the constant CONTINUE has the value 0, WON has the value 1 and LOST has the value 2. enum Status { CONTINUE, WON, LOST };  Another popular enumeration is enum Months { JAN = 1, FEB, MAR, APR, MAY, JUN, JUL, AUG, SEP, OCT, NOV, DEC }; 22
  • 23.
    Concatenating String  The+ operator cannot be used to concatenate C-strings. That is, you can’t say str3 = str1 + str2;  The program first displays three strings separately.  The third is empty at this point, so nothing is printed when it displays itself.  Then the first two strings are concatenated and placed in the third, and the third string is displayed again.  The declarator String operator + (String ss) shows that the + operator takes one argument of type String and returns an object of the same type.  The concatenation process in operator+() involves creating a temporary object of type String, copying the string from our own String object into it, concatenating the argument string using the library function strcat(), and returning the resulting temporary string. 23
  • 24.
    Concatenating String  Notethat we can’t use the return String(string); approach, where a nameless temporary String is created,  because we need access to the temporary String not only to initialize it, but to concatenate the argument string to it.  We must be careful that we don’t overflow the fixed-length strings used in the String class. To prevent such accidents in the operator+() function, we check that the combined length of the two strings to be concatenated will not exceed the maximum string length.  We’ve seen different uses of the + operator: to add English 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. 24
  • 25.
    Example 7: OverloadingComparison (<) Operator (1/2) // overloaded '<' operator compares two Distances #include <iostream> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) { } // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } bool operator < (Distance) const; // compare distances }; 25
  • 26.
    Example 7: OverloadingComparison (<) Operator (2/2) bool Distance::operator < (Distance d2) const { float bf1 = feet + inches / 12; float bf2 = d2.feet + d2.inches / 12; return bf1 < bf2; } int main() { Distance dist1; // define Distance dist1 dist1.getdist(); // get dist1 from user Distance dist2(6, 2.5); // define and initialize dist2 cout << "ndist1 = "; dist1.showdist(); // display distances cout << "ndist2 = "; dist2.showdist(); if (dist1 < dist2) // overloaded '<' operator cout << "ndist1 is less than dist2"; else cout << "ndist1 is greater than (or equal to) dist2"; cout << endl; system("PAUSE"); return 0; } 26
  • 27.
    Overloading Comparison (<)Operator  The approach used in the operator < () function is similar to overloading the + operator, except that here the operator < () function has a return type of bool.  The return value is false or true, depending on the comparison of the two distances.  The comparison is made by converting both distances to floating-point feet, and comparing them using the normal < operator.  Remember that the use of the conditional operator return (bf1 < bf2) ? true : false; is the same as if(bf1 < bf2) return true; else return false; 27
  • 28.
    Example 8: OverloadingComparison (==) Operator (1/2) // overloaded '==' operator compares strings #include <iostream> #include <string.h> // for strcmp() using namespace std; class String { // user-defined string type private: enum { SZ = 80 }; // size of String objects char str[SZ]; // holds a string public: String() { // constructor, no args strcpy_s(str, ""); } String(const char *s) { // constructor, one arg strcpy_s(str, s); } void display() const { // display a String cout << str; } 28
  • 29.
    Example 8: OverloadingComparison (==) Operator (2/2) void getstr() { // read a string cin.get(str, SZ); } bool operator == (String ss) const { // check for equality return !strcmp(str, ss.str); } }; int main() { String s1 = "yes", s2 = "no", s3; cout << "nEnter 'yes' or 'no': "; s3.getstr(); // get String from user if (s3 == s1) cout << "You typed yesn"; // compare with "yes" else if (s3 == s2) cout << "You typed non"; // compare with "no" else cout << "You didn’t follow instructionsn"; system("PAUSE"); return 0; } 29
  • 30.
    Example 9: OverloadingComparison (+=) Operator (1/2) // englpleq.cpp overloaded '+=' assignment operator #include <iostream> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) { } // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } void operator += (Distance); }; 30
  • 31.
    Example 9: OverloadingComparison (+=) Operator (2/2) void Distance::operator += (Distance d2) { // add distance to this one feet += d2.feet; // add the feet inches += d2.inches; // add the inches if (inches >= 12.0) { // if total exceeds 12.0, inches -= 12.0; // then decrease inches by 12.0 feet++; // and increase feet by 1 } } int main() { Distance dist1; // define dist1 dist1.getdist(); // get dist1 from user cout << "ndist1 = "; dist1.showdist(); Distance dist2(11, 6.25); // define, initialize dist2 cout << "ndist2 = "; dist2.showdist(); dist1 += dist2; // dist1 = dist1 + dist2 cout << "nAfter addition,"; cout << "ndist1 = "; dist1.showdist(); cout << endl; system("PAUSE"); return 0; } 31
  • 32.
    Arithmetic Assignment (+=)Operators  In the operator +=() function in program, the object that takes on the value of the sum is the object of which the function is a member.  Thus it is feet and inches that are given values, not temporary variables used only to return an object. The operator+=() function has no return value; it returns type void.  A return value is not necessary with arithmetic assignment operators such as +=, because the result of the assignment operator is not assigned to anything.  The operator is used alone, in expressions like the one in the program. dist1 += dist2;  If you wanted to use this operator in more complex expressions, like dist3 = dist1 += dist2;  then you would need to provide a return value (i.e. a distance object). 32
  • 33.
    Example 10: Separategetel() and putel() Functions (1/2) // creates safe array uses separate put and get functions #include <iostream> #include <process.h> // for exit() using namespace std; const int LIMIT = 100; class safearay { private: int arr[LIMIT]; public: void putel(int n, int elvalue) { // set value of element if (n < 0 || n >= LIMIT) { cout << "nIndex out of bounds"; system("PAUSE"); exit(1); } arr[n] = elvalue; } 33
  • 34.
    Example 10: Separategetel() and putel() Functions (2/2) int getel(int n) const { // get value of element if (n < 0 || n >= LIMIT) { cout << "nIndex out of bounds"; system("PAUSE"); exit(1); } return arr[n]; } }; int main() { safearay sa1; for (int j = 0; j < LIMIT; j++) // insert elements sa1.putel(j, j * 10); for (int j = 0; j < LIMIT; j++) { // display elements int temp = sa1.getel(j); cout << "Element " << j << " is " << temp << endl; } system("PAUSE"); return 0; } 34
  • 35.
    Ex 11: Singleaccess() Function Returning by Reference (1/2) // uses one access() function for both put and get #include <iostream> #include <process.h> // for exit() using namespace std; const int LIMIT = 100; // array size class safearay { private: int arr[LIMIT]; public: int& access(int n) { if (n < 0 || n >= LIMIT) { cout << "n Index out of bounds"; system("PAUSE"); exit(1); } return arr[n]; } }; 35
  • 36.
    Ex 11: Singleaccess() Function Returning by Reference (2/2) int main() { safearay sa1; for (int j = 0; j < LIMIT; j++) // insert elements sa1.access(j) = j * 10; // *left* side of equal sign for (int j = 0; j < LIMIT; j++) { // display elements int temp = sa1.access(j); //*right* side of equal sign cout << "Element " << j << " is " << temp << endl; } system("PAUSE"); return 0; } 36
  • 37.
    Ex 12: Overloaded[] Operator Returning by Reference (1/2) // creates safe array, uses overloaded [] operator for both put and get #include <iostream> #include <process.h> // for exit() const int LIMIT = 100; // array size using namespace std; class safearay { private: int arr[LIMIT]; public: int& operator [](int n) { if (n < 0 || n >= LIMIT) { cout << "n Index out of bounds"; exit(1); } return arr[n]; } }; 37
  • 38.
    Ex 12: Overloaded[] Operator Returning by Reference (2/2) int main() { safearay sa1; for (int j = 0; j < LIMIT; j++) // insert elements sa1[j] = j * 10; // *left* side of equal sign for (int j = 0; j < LIMIT; j++) // display elements { int temp = sa1[j]; // *right* side of equal sign cout << "Element " << j << " is " << temp << endl; } system("PAUSE"); return 0; } 38
  • 39.
    Ex 13: ConversionBetween Objects and Basic Types (1/3) // conversions: Distance to meters, meters to Distance #include <iostream> using namespace std; class Distance { // English Distance class private: const float MTF; // meters to feet int feet; float inches; public: Distance() : feet(0), inches(0.0), MTF(3.280833F) { } // constructor (one arg) Distance(float meters) : MTF(3.280833F) { // convert meters to Distance float fltfeet = MTF * meters; // convert to float feet feet = int(fltfeet); // feet is integer part inches = 12 * (fltfeet - feet); // inches is what’s left } 39
  • 40.
    Ex 13: ConversionBetween Objects and Basic Types (2/3) Distance(int ft, float in) : feet(ft), inches(in), MTF(3.280833F) { } // constructor (two args) void getdist() { // get length from user cout << "nEnter feet: "; cin >> feet; cout << "Enter inches: "; cin >> inches; } void showdist() const { // display distance cout << feet << "'-" << inches << '"'; } operator float() const // conversion operator { // converts Distance to meters float fracfeet = inches / 12; // convert the inches fracfeet += static_cast<float>(feet); //add the feet return fracfeet / MTF; // convert to meters } }; 40
  • 41.
    Ex 13: ConversionBetween Objects and Basic Types (3/3) int main() { float mtrs; Distance dist1 = 2.35F; // uses 1-arg constructor to convert meters to Distance cout << "ndist1 = "; dist1.showdist(); mtrs = static_cast<float>(dist1); // uses conversion operator cout << "ndist1 = " << mtrs << " metersn"; // for Distance to meters Distance dist2(5, 10.25); // uses 2-arg constructor mtrs = dist2; // also uses conversion op cout << "ndist2 = " << mtrs << " metersn"; // dist2 = mtrs; // error, = won’t convert system("PAUSE"); return 0; } 41
  • 42.
    Ex 14: ConversionBetween C-String and String Objects (1/2) // conversion between ordinary strings and class String #include <iostream> #include <string.h> // for strcpy_s(), etc. using namespace std; class String { // user-defined string type private: enum { SZ = 80 }; // size of all String objects char str[SZ]; // holds a C-string public: String() { str[0] = '0'; } // no-arg constructor String(const char s[]) { // 1-arg constructor converts C-string to String Object strcpy_s(str, s); } void display() const { // display the String cout << str << endl; } operator char* () { // conversion operator converts String to C-string return str; } }; 42
  • 43.
    Ex 14: ConversionBetween C-String and String Objects (2/2) int main() { String s1; // uses no-arg constructor char xstr[] = "Hello World "; // create and initialize C-string s1 = xstr; // uses 1-arg constructor to convert C-string to String Object s1.display(); // display String String s2 = "Good Morning "; // uses 1-arg constructor to initialize String cout << static_cast<char*>(s2); // use conversion operator to convert String to C-string // before sending to << op cout << endl; system("PAUSE"); return 0; } 43
  • 44.
    Ex 15: ConversionsBetween Objects of Different Classes (1/3) // converts from Polar Coordinates to Cartesian Coordinates // using 1-Arg constructor in the Cartesian Class #define M_PI 3.14159265358979323846 // value of pi #include <math.h> #include <iostream> #include <string> using namespace std; class Polar { // for 2D Polar Coordinates public: double R; // Radius double Theta; // Theta in Degrees Polar() : R(0), Theta(0) { } Polar(double R, double Theta) : R(R), Theta(Theta) { } void Show() const { cout << "R = " << R << ", Theta = " << Theta << " Degrees" << endl; } }; 44 X Y r θ y x P(x,y) Cartesian P(r,θ) Polar
  • 45.
    Ex 15: ConversionsBetween Objects of Different Classes (2/3) class Cartesian { // for 2D Cartesian Coordinates public: double X, Y; Cartesian() : X(0), Y(0) { } Cartesian(double X, double Y) : X(X), Y(Y) { } Cartesian(Polar P) { double r, t; r = P.R; // Get Radius t = P.Theta; // Get Theta t *= M_PI / 180; // Convert Degrees to Radians X = r * cos(t); // Calculate X Y = r * sin(t); // Calculate Y } void Show() const { cout << "X = " << X << ", Y = " << Y << endl; } }; 45 X Y r θ y x P(x,y) Cartesian P(r,θ) Polar
  • 46.
    Ex 15: ConversionsBetween Objects of Different Classes (3/3) int main() { Polar Pol(5, 53.13); // R = 5, Theta = 53.13 Degrees Cartesian Cat = Pol; // Convert Polar to Cartesian Pol.Show(); // Show in Polar Cat.Show(); // Show in Cartesian system("PAUSE"); return 0; } 46
  • 47.
    Ex 16: ConversionsBetween Objects of Different Classes (1/3) // converts from Polar Coordinates to Cartesian Coordinates using Operator Overloading in // Polar Class #define M_PI 3.14159265358979323846 //pi #include <math.h> #include <iostream> #include <string> using namespace std; class Cartesian // A Class for 2D Cartesian Coordinates { public: double X, Y; Cartesian() : X(0), Y(0) { } Cartesian(double X, double Y) : X(X), Y(Y) { } void Show() const { cout << "X = " << X << ", Y = " << Y << endl; } }; 47
  • 48.
    Ex 16: ConversionsBetween Objects of Different Classes (2/3) class Polar { // for 2D Polar Coordinates public: double R; // Radius double Theta; // Theta in Degrees public: Polar() : R(0), Theta(0) { } Polar(double R, double Theta) : R(R), Theta(Theta) { } void Show() const { cout << "R = " << R << ", Theta = " << Theta << " Degrees" << endl; } operator Cartesian() const { double x, y, t; t = Theta * M_PI / 180; // Converts Degrees to Radians x = R * cos(t); y = R * sin(t); return Cartesian(x, y); } }; 48 X Y r θ y x P(x,y) Cartesian P(r,θ) Polar
  • 49.
    Ex 16: ConversionsBetween Objects of Different Classes (3/3) int main() { Polar Pol(5, 53.13); // R = 5, Theta = 53.13 Degrees Cartesian Cat = Pol; // Convert Polar to Cartesian Pol.Show();// Show in Polar Cat.Show();// Show in Cartesian system("PAUSE"); return 0; } 49
  • 50.
    Preventing Conversions withexplicit  You can call fancyDist() with arguments Distance variable is no problem.  you can also call fancyDist() with a variable of type float as the argument: fancyDist(mtrs);  The compiler will realize it’s the wrong type and look for a conversion operator.  Finding a Distance constructor that takes type float as an argument, it will arrange for this constructor to convert float to Distance and pass the Distance value to the function.  This is an implicit conversion, one which you may not have intended to make possible.  However, if we make the constructor explicit, we prevent implicit conversions.  You can check this by removing the comment symbol from the call to fancyDist() in the program: 50
  • 51.
    Preventing Conversions withexplicit  The compiler will tell you it can’t perform the conversion. Without the explicit keyword, this call is perfectly legal.  As a side effect of the explicit constructor, note that you can’t use the form of object initialization that uses an equal sign Distance dist1 = 2.35F;  Whereas the form with parentheses works as it always has: Distance dist1(2.35F);  Ordinarily, when you create a const object, you want a guarantee that none of its member data can be changed. However, a situation occasionally arises where you want to create const objects that have some specific member data item that needs to be modified despite the object’s constness.  Let’s say we want to be able to create const scrollbars in which attributes remain unchanged, except for their ownership. That’s where the mutable keyword comes in. 51
  • 52.
    Ex 17: PreventingConversions with explicit (1/2) #include <iostream> using namespace std; class Distance { private: const float MTF; //meters to feet int feet; float inches; public: //no-args constructor Distance() : feet(0), inches(0.0), MTF(3.280833F) { } // EXPLICIT one-arg constructor explicit Distance(float meters) : MTF(3.280833F) { float fltfeet = MTF * meters; feet = int(fltfeet); inches = 12*(fltfeet-feet); } void showdist(){ cout << feet << "'-" << inches << '"'; } }; 52
  • 53.
    Ex 17: PreventingConversions with explicit (2/2) int main(){ void fancyDist(Distance); //declaration Distance dist1(2.35F); //uses 1-arg constructor to convert meters to Distance // Distance dist1 = 2.35F; // ERROR if constructor is explicit cout << "ndist1 = "; dist1.showdist(); float mtrs = 3.0F; // fancyDist(mtrs); // ERROR if constructor is explicit return 0; } void fancyDist(Distance d) { cout << "(in feet and inches) = "; d.showdist(); cout << endl; } 53
  • 54.
    Ex 18: Changingconst Object Data Using mutable (1/2) #include <iostream> #include <string> using namespace std; class scrollbar { private: int size; // related to constness mutable string owner; // not relevant to constness public: scrollbar(int sz, string own) : size(sz), owner(own){ } void setSize(int sz) : size(sz) { } // changes size void setOwner(string own) const { // changes owner owner = own; } int getSize() const { // returns size return size; } string getOwner() const { // returns owner return owner; } }; 54
  • 55.
    Ex 18: Changingconst Object Data Using mutable (1/2) int main() { const scrollbar sbar(60, "Window1"); // sbar.setSize(100); // can’t do this to const obj sbar.setOwner("Window2"); // this is OK // these are OK too cout << sbar.getSize() << ", " << sbar.getOwner() << endl; system("PAUSE"); return 0; } 55
  • 56.
    Ex 19: streaminsertion (<<) & extraction (>>) operator (1/2) // stream insertion (<<) and stream extraction (>>) operator #include <iostream> using namespace std; class Distance { // English Distance class private: int feet; float inches; public: Distance() : feet(0), inches(0.0) { } // constructor (no args) Distance(int ft, float in) : feet(ft), inches(in){ } friend istream& operator >> (istream& input , Distance& dist); friend ostream& operator << (ostream& output, const Distance& dist); }; // overloading of stream extraction operator istream& operator >> (istream& input, Distance& dist) { cout << "Enter Feet: "; input >> dist.feet; cout << "Enter Inches: "; input >> dist.inches; return input; } 56
  • 57.
    Ex 19: streaminsertion (<<) & extraction (>>) operator (2/2) // overloading of stream insertion operator ostream& operator << (ostream& output, const Distance& dist) { output << dist.feet << "'-"<< dist.inches << '"'; return output; } int main() { Distance dist1; // define Distance dist1 cin >> dist1; // now calling stream extraction operator >> cout << "You Entered: " << dist1 << endl; // now calling stream insertion operator << system("PAUSE"); return 0; } 57
  • 58.
    Summary 58 These operators canbe overloaded in C++ ++ -- ! ~ - + * / % ^ & && | || < << > >> != ~= += -= *= /= %= ^= &= &&= |= ||= <= <<= >= >>= == [] = -> ->* () , new delete new[ ] delete[ ] These operators cannot be overloaded in C++ . .* :: ?: sizeof
  • 59.
    Assignment # 2 59 AssignmentNo.2.doc Assignment No.2.pdf