Wrap-Up

Answers to Self Review Exercises

11.1

a) operator overloading. b) operator. c) assignment (=), address (&), comma (,). d) precedence, associativity, "arity."

11.2

Operator >> is both the right-shift operator and the stream extraction operator, depending on its context. Operator << is both the left-shift operator and the stream insertion operator, depending on its context.

11.3

For operator overloading: It would be the name of a function that would provide an overloaded version of the / operator for a specific class.

11.4

True.

11.5

The precedence is identical.

Exercises

11.6

Give as many examples as you can of operator overloading implicit in C++. Give a reasonable example of a situation in which you might want to overload an operator explicitly in C++.

11.7

The operators that cannot be overloaded are __________, __________, __________ and __________.

11.8

String concatenation requires two operandsthe two strings that are to be concatenated. In the text, we showed how to implement an overloaded concatenation operator that concatenates the second String object to the right of the first String object, thus modifying the first String object. In some applications, it is desirable to produce a concatenated String object without modifying the String arguments. Implement operator+ to allow operations such as

string1 = string2 + string3;

11.9

(Ultimate operator overloading exercise) To appreciate the care that should go into selecting operators for overloading, list each of C++'s overloadable operators, and for each, list a possible meaning (or several, if appropriate) for each of several classes you have studied in this text. We suggest you try:

  1. Array
  2. Stack
  3. String

After doing this, comment on which operators seem to have meaning for a wide variety of classes. Which operators seem to be of little value for overloading? Which operators seem ambiguous?

11.10

Now work the process described in Exercise 11.9 in reverse. List each of C++'s overloadable operators. For each, list what you feel is perhaps the "ultimate operation" the operator should be used to represent. If there are several excellent operations, list them all.

11.11

One nice example of overloading the function call operator () is to allow another form of double-array subscripting popular in some programming languages. Instead of saying

chessBoard[ row ][ column ]  


for an array of objects, overload the function call operator to allow the alternate form

chessBoard( row, column )  

Create a class DoubleSubscriptedArray that has similar features to class Array in Figs. 11.611.7. At construction time, the class should be able to create an array of any number of rows and any number of columns. The class should supply operator() to perform double-subscripting operations. For example, in a 3-by-5 DoubleSubscriptedArray called a, the user could write a( 1, 3 ) to access the element at row 1 and column 3. Remember that operator() can receive any number of arguments (see class String in Figs. 11.911.10 for an example of operator()). The underlying representation of the double-subscripted array should be a single-subscripted array of integers with rows * columns number of elements. Function operator() should perform the proper pointer arithmetic to access each element of the array. There should be two versions of operator()one that returns int & (so that an element of a DoubleSubscriptedArray can be used as an lvalue) and one that returns const int & (so that an element of a const DoubleSubscriptedArray can be used only as an rvalue). The class should also provide the following operators: ==, !=, =, << (for outputting the array in row and column format) and >> (for inputting the entire array contents).

11.12

Overload the subscript operator to return the largest element of a collection, the second largest, the third largest, and so on.

11.13

Consider class Complex shown in Figs. 11.1911.21. The class enables operations on so-called complex numbers. These are numbers of the form realPart + imaginaryPart * i, where i has the value

 
  1. Modify the class to enable input and output of complex numbers through the overloaded >> and << operators, respectively (you should remove the print function from the class).
  2. Overload the multiplication operator to enable multiplication of two complex numbers as in algebra.
  3. Overload the == and != operators to allow comparisons of complex numbers.

Figure 11.19. Complex class definition.

1 // Fig. 11.19: Complex.h 2 // Complex class definition. 3 #ifndef COMPLEX_H 4 #define COMPLEX_H 5 6 class Complex 7 { 8 public: 9 Complex( double = 0.0, double = 0.0 ); // constructor 10 Complex operator+( const Complex & ) const; // addition 11 Complex operator-( const Complex & ) const; // subtraction 12 void print() const; // output 13 private: 14 double real; // real part 15 double imaginary; // imaginary part 16 }; // end class Complex 17 18 #endif


Figure 11.20. Complex class member-function definitions.

1 // Fig. 11.20: Complex.cpp 2 // Complex class member-function definitions. 3 #include 4 using std::cout; 5 6 #include "Complex.h" // Complex class definition 7 8 // Constructor 9 Complex::Complex( double realPart, double imaginaryPart ) 10 : real( realPart ), 11 imaginary( imaginaryPart ) 12 { 13 // empty body 14 } // end Complex constructor 15 16 // addition operator 17 Complex Complex::operator+( const Complex &operand2 ) const 18 { 19 return Complex( real + operand2.real, 20 imaginary + operand2.imaginary ); 21 } // end function operator+ 22 23 // subtraction operator 24 Complex Complex::operator-( const Complex &operand2 ) const 25 { 26 return Complex( real - operand2.real, 27 imaginary - operand2.imaginary ); 28 } // end function operator- 29 30 // display a Complex object in the form: (a, b) 31 void Complex::print() const 32 { 33 cout << '(' << real << ", " << imaginary << ')'; 34 } // end function print

Figure 11.21. Complex numbers.

(This item is displayed on pages 627 - 628 in the print version)

1 // Fig. 11.21: fig11_21.cpp 2 // Complex class test program. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include "Complex.h" 8 9 int main() 10 { 11 Complex x; 12 Complex y( 4.3, 8.2 ); 13 Complex z( 3.3, 1.1 ); 14 15 cout << "x: "; 16 x.print(); 17 cout << " y: "; 18 y.print(); 19 cout << " z: "; 20 z.print(); 21 22 x = y + z; 23 cout << " x = y + z:" << endl; 24 x.print(); 25 cout << " = "; 26 y.print(); 27 cout << " + "; 28 z.print(); 29 30 x = y - z; 31 cout << " x = y - z:" << endl; 32 x.print(); 33 cout << " = "; 34 y.print(); 35 cout << " - "; 36 z.print(); 37 cout << endl; 38 return 0; 39 } // end main  

x: (0, 0) y: (4.3, 8.2) z: (3.3, 1.1) x = y + z: (7.6, 9.3) = (4.3, 8.2) + (3.3, 1.1) x = y - z: (1, 7.1) = (4.3, 8.2) - (3.3, 1.1)  

 
11.14

A machine with 32-bit integers can represent integers in the range of approximately 2 billion to +2 billion. This fixed-size restriction is rarely troublesome, but there are applications in which we would like to be able to use a much wider range of integers. This is what C++ was built to do, namely, create powerful new data types. Consider class HugeInt of Figs. 11.2211.24. Study the class carefully, then answer the following:

  1. Describe precisely how it operates.
  2. What restrictions does the class have?
  3. Overload the * multiplication operator.
  4. Overload the / division operator.
  5. Overload all the relational and equality operators.

[Note: We do not show an assignment operator or copy constructor for class HugeInteger, because the assignment operator and copy constructor provided by the compiler are capable of copying the entire array data member properly.]


Figure 11.22. HugeInt class definition.

1 // Fig. 11.22: Hugeint.h 2 // HugeInt class definition. 3 #ifndef HUGEINT_H 4 #define HUGEINT_H 5 6 #include 7 using std::ostream; 8 9 class HugeInt 10 { 11 friend ostream &operator<<( ostream &, const HugeInt & ); 12 public: 13 HugeInt( long = 0 ); // conversion/default constructor 14 HugeInt( const char * ); // conversion constructor 15 16 // addition operator; HugeInt + HugeInt 17 HugeInt operator+( const HugeInt & ) const; 18 19 // addition operator; HugeInt + int 20 HugeInt operator+( int ) const; 21 22 // addition operator; 23 // HugeInt + string that represents large integer value 24 HugeInt operator+( const char * ) const; 25 private: 26 short integer[ 30 ]; 27 }; // end class HugetInt 28 29 #endif

11.15

Create a class RationalNumber (fractions) with the following capabilities:

  1. Create a constructor that prevents a 0 denominator in a fraction, reduces or simplifies fractions that are not in reduced form and avoids negative denominators.
  2. Overload the addition, subtraction, multiplication and division operators for this class.
  3. Overload the relational and equality operators for this class.

11.16

Study the C string-handling library functions and implement each of the functions as part of class String (Figs. 11.911.10). Then, use these functions to perform text manipulations.

11.17

Develop class Polynomial. The internal representation of a Polynomial is an array of terms. Each term contains a coefficient and an exponent. The term

2x4

has the coefficient 2 and the exponent 4. Develop a complete class containing proper constructor and destructor functions as well as set and get functions. The class should also provide the following overloaded operator capabilities:

  1. Overload the addition operator (+) to add two Polynomials.
  2. Overload the subtraction operator (-) to subtract two Polynomials.
  3. Overload the assignment operator to assign one Polynomial to another.
  4. Overload the multiplication operator (*) to multiply two Polynomials.
  5. Overload the addition assignment operator (+=), subtraction assignment operator (-=), and multiplication assignment operator (*=).


Figure 11.23. HugeInt class member-function and friend-function definitions.

(This item is displayed on pages 630 - 631 in the print version)

1 // Fig. 11.23: Hugeint.cpp 2 // HugeInt member-function and friend-function definitions. 3 #include // isdigit function prototype 4 #include // strlen function prototype 5 #include "Hugeint.h" // HugeInt class definition 6 7 // default constructor; conversion constructor that converts 8 // a long integer into a HugeInt object 9 HugeInt::HugeInt( long value ) 10 { 11 // initialize array to zero 12 for ( int i = 0; i <= 29; i++ ) 13 integer[ i ] = 0; 14 15 // place digits of argument into array 16 for ( int j = 29; value != 0 && j >= 0; j-- ) 17 { 18 integer[ j ] = value % 10; 19 value /= 10; 20 } // end for 21 } // end HugeInt default/conversion constructor 22 23 // conversion constructor that converts a character string 24 // representing a large integer into a HugeInt object 25 HugeInt::HugeInt( const char *string ) 26 { 27 // initialize array to zero 28 for ( int i = 0; i <= 29; i++ ) 29 integer[ i ] = 0; 30 31 // place digits of argument into array 32 int length = strlen( string ); 33 34 for ( int j = 30 - length, k = 0; j <= 29; j++, k++ ) 35 36 if ( isdigit( string[ k ] ) ) 37 integer[ j ] = string[ k ] - '0'; 38 } // end HugeInt conversion constructor 39 40 // addition operator; HugeInt + HugeInt 41 HugeInt HugeInt::operator+( const HugeInt &op2 ) const 42 { 43 HugeInt temp; // temporary result 44 int carry = 0; 45 46 for ( int i = 29; i >= 0; i-- ) 47 { 48 temp.integer[ i ] = 49 integer[ i ] + op2.integer[ i ] + carry; 50 51 // determine whether to carry a 1 52 if ( temp.integer[ i ] > 9 ) 53 { 54 temp.integer[ i ] %= 10; // reduce to 0-9 55 carry = 1; 56 } // end if 57 else // no carry 58 carry = 0; 59 } // end for 60 61 return temp; // return copy of temporary object 62 } // end function operator+ 63 64 // addition operator; HugeInt + int 65 HugeInt HugeInt::operator+( int op2 ) const 66 { 67 // convert op2 to a HugeInt, then invoke 68 // operator+ for two HugeInt objects 69 return *this + HugeInt( op2 ); 70 } // end function operator+ 71 72 // addition operator; 73 // HugeInt + string that represents large integer value 74 HugeInt HugeInt::operator+( const char *op2 ) const 75 { 76 // convert op2 to a HugeInt, then invoke 77 // operator+ for two HugeInt objects 78 return *this + HugeInt( op2 ); 79 } // end operator+ 80 81 // overloaded output operator 82 ostream& operator<<( ostream &output, const HugeInt &num ) 83 { 84 int i; 85 86 for ( i = 0; ( num.integer[ i ] == 0 ) && ( i <= 29 ); i++ ) 87 ; // skip leading zeros 88 89 if ( i == 30 ) 90 output << 0; 91 else 92 93 for ( ; i <= 29; i++ ) 94 output << num.integer[ i ]; 95 96 return output; 97 } // end function operator<<

 
11.18

In the program of Figs. 11.311.5, Fig. 11.4 contains the comment "overloaded stream insertion operator; cannot be a member function if we would like to invoke it with cout << somePhoneNumber;." Actually, the stream insertion operator could be a PhoneNumber class member function if we were willing to invoke it either as somePhoneNumber.operator<<( cout ); or as somePhoneNumber << cout;. Rewrite the program of Fig. 11.5 with the overloaded stream insertion operator<< as a member function and try the two preceding statements in the program to demonstrate that they work.


Figure 11.24. Huge integers.

1 // Fig. 11.24: fig11_24.cpp 2 // HugeInt test program. 3 #include 4 using std::cout; 5 using std::endl; 6 7 #include "Hugeint.h" 8 9 int main() 10 { 11 HugeInt n1( 7654321 ); 12 HugeInt n2( 7891234 ); 13 HugeInt n3( "99999999999999999999999999999" ); 14 HugeInt n4( "1" ); 15 HugeInt n5; 16 17 cout << "n1 is " << n1 << " n2 is " << n2 18 << " n3 is " << n3 << " n4 is " << n4 19 << " n5 is " << n5 << " "; 20 21 n5 = n1 + n2; 22 cout << n1 << " + " << n2 << " = " << n5 << " "; 23 24 cout << n3 << " + " << n4 << " = " << ( n3 + n4 ) << " "; 25 26 n5 = n1 + 9; 27 cout << n1 << " + " << 9 << " = " << n5 << " "; 28 29 n5 = n2 + "10000"; 30 cout << n2 << " + " << "10000" << " = " << n5 << endl; 31 return 0; 32 } // end main  

n1 is 7654321 n2 is 7891234 n3 is 99999999999999999999999999999 n4 is 1 n5 is 0 7654321 + 7891234 = 15545555 99999999999999999999999999999 + 1 = 100000000000000000000000000000 7654321 + 9 = 7654330 7891234 + 10000 = 7901234  

Категории