[Page 625 (
continued
)]
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 ]
[Page 626]
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
|
[Page 627]
Figure 11.20.
Complex
class
member-function
definitions.
1
// Fig. 11.20: Complex.cpp
2
// Complex class member-function definitions.
3
#include
<iostream>
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
<iostream>
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 <<
"\ny: "
;
18 y.print();
19 cout <<
"\nz: "
;
20 z.print();
21
22 x = y + z;
23 cout <<
"\n\nx = y + z:"
<< endl;
24 x.print();
25 cout <<
" = "
;
26 y.print();
27 cout <<
" + "
;
28 z.print();
29
30 x = y - z;
31 cout <<
"\n\nx = y - z:"
<< endl;
32 x.print();
33 cout <<
" = "
;
34 y.print();
35 cout <<
" - "
;
36 z.print();
37 cout << endl;
38
return
;
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)
|
|
|
|
|
[Page 628]
|
|
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.]
[Page 629]
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
<iostream>
7
using
std::ostream;
8
9
class
HugeInt
10 {
11
friend
ostream &
operator
<<( ostream &,
const
HugeInt & );
12
public
:
13 HugeInt(
long
=
);
// 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
2x
4
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
Polynomial
s.
-
Overload the subtraction operator (
-
) to subtract two
Polynomial
s.
-
Overload the assignment operator to assign one
Polynomial
to another.
-
Overload the multiplication operator (
*
) to multiply two
Polynomial
s.
-
Overload the addition assignment operator (
+=
), subtraction assignment operator (
-=
), and multiplication assignment operator (
*=
).
[Page 630]
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
<cctype>
// isdigit function prototype
4
#include
<cstring>
// 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 =
; i <=
29
; i++ )
13 integer[ i ] =
;
14
15
// place digits of argument into array
16
for
(
int
j =
29
; value !=
&& j >=
; 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 =
; i <=
29
; i++ )
29 integer[ i ] =
;
30
31
// place digits of argument into array
32
int
length = strlen( string );
33
34
for
(
int
j =
30
- length, k =
; 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 =
;
45
46
for
(
int
i =
29
; i >=
; 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 =
;
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 =
; ( num.integer[ i ] ==
) && ( i <=
29
); i++ )
87 ;
// skip leading zeros
88
89
if
( i ==
30
)
90 output <<
;
91
else
92
93
for
( ; i <=
29
; i++ )
94 output << num.integer[ i ];
95
96
return
output;
97 }
// end function operator<<
|
|
|
|
[Page 631]
|
|
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.
[Page 632]
Figure 11.24. Huge integers.
1
// Fig. 11.24: fig11_24.cpp
2
// HugeInt test program.
3
#include
<iostream>
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 <<
"\nn2 is "
<< n2
18 <<
"\nn3 is "
<< n3 <<
"\nn4 is "
<< n4
19 <<
"\nn5 is "
<< n5 <<
"\n\n"
;
20
21 n5 = n1 + n2;
22 cout << n1 <<
" + "
<< n2 <<
" = "
<< n5 <<
"\n\n"
;
23
24 cout << n3 <<
" + "
<< n4 <<
"\n= "
<< ( n3 + n4 ) <<
"\n\n"
;
25
26 n5 = n1 +
9
;
27 cout << n1 <<
" + "
<< 9 <<
" = "
<< n5 <<
"\n\n"
;
28
29 n5 = n2 +
"10000"
;
30 cout << n2 <<
" + "
<<
"10000"
<<
" = "
<< n5 << endl;
31
return
;
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
|
|
|
|