Flylib.com

Books Software

 
 
 

Exercises


[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:

  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 ]



[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


  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



[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:

  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.]


[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:

  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

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:

  1. Overload the addition operator ( + ) to add two Polynomial s.

  2. Overload the subtraction operator ( - ) to subtract two Polynomial s.

  3. Overload the assignment operator to assign one Polynomial to another.

  4. Overload the multiplication operator ( * ) to multiply two Polynomial s.

  5. 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