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:
- Array
- Stack
- 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
- 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).
- Overload the multiplication operator to enable multiplication of two complex numbers as in algebra.
- 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:
- Describe precisely how it operates.
- What restrictions does the class have?
- Overload the * multiplication operator.
- Overload the / division operator.
- 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:
- 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.
- Overload the addition, subtraction, multiplication and division operators for this class.
- 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:
- Overload the addition operator (+) to add two Polynomials.
- Overload the subtraction operator (-) to subtract two Polynomials.
- Overload the assignment operator to assign one Polynomial to another.
- Overload the multiplication operator (*) to multiply two Polynomials.
- 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
|
|
|
|