The program of Figs. 10.9–10.11 demonstrates class Array
and its overloaded operators. First we walk through main
(Fig. 10.9) and the program’s output, then we consider the class definition (Fig. 10.10) and each of its member-function definitions (Fig. 10.11).
1 // Fig. 10.9: fig10_09.cpp
2 // Array class test program.
3 #include <iostream>
4 #include <stdexcept>
5 #include "Array.h"
6 using namespace std;
7
8 int main()
9 {
10 Array integers1( 7 ); // seven-element Array
11 Array integers2; // 10-element Array by default
12
13 // print integers1 size and contents
14 cout << "Size of Array integers1 is "
15 << integers1.getSize()
16 << "
Array after initialization:
" << integers1;
17
18 // print integers2 size and contents
19 cout << "
Size of Array integers2 is "
20 << integers2.getSize()
21 << "
Array after initialization:
" << integers2;
22
23 // input and print integers1 and integers2
24 cout << "
Enter 17 integers:" << endl;
25 cin >> integers1 >> integers2;
26
27 cout << "
After input, the Arrays contain:
"
28 << "integers1:
" << integers1
29 << "integers2:
" << integers2;
30
31 // use overloaded inequality (!=) operator
32 cout << "
Evaluating: integers1 != integers2" << endl;
33
34 if ( integers1 != integers2 )
35 cout << "integers1 and integers2 are not equal" << endl;
36
37 // create Array integers3 using integers1 as an
38 // initializer; print size and contents
39 Array integers3( integers1 ); // invokes copy constructor
40
41 cout << "
Size of Array integers3 is "
42 << integers3.getSize()
43 << "
Array after initialization:
" << integers3;
44
45 // use overloaded assignment (=) operator
46 cout << "
Assigning integers2 to integers1:" << endl;
47 integers1 = integers2; // note target Array is smaller
48
49 cout << "integers1:
" << integers1
50 << "integers2:
" << integers2;
51
52 // use overloaded equality (==) operator
53 cout << "
Evaluating: integers1 == integers2" << endl;
54
55 if ( integers1 == integers2 )
56 cout << "integers1 and integers2 are equal" << endl;
57
58 // use overloaded subscript operator to create rvalue
59 cout << "
integers1[5] is " << integers1[ 5 ];
60
61 // use overloaded subscript operator to create lvalue
62 cout << "
Assigning 1000 to integers1[5]" << endl;
63 integers1[ 5 ] = 1000;
64 cout << "integers1:
" << integers1;
65
66 // attempt to use out-of-range subscript
67 try
68 {
69 cout << "
Attempt to assign 1000 to integers1[15]" << endl;
70 integers1[ 15 ] = 1000; // ERROR: subscript out of range
71 } // end try
72 catch ( out_of_range &ex )
73 {
74 cout << "An exception occurred: " << ex.what() << endl;
75 } // end catch
76 } // end main
Size of Array integers1 is 7
Array after initialization:
0 0 0 0
0 0 0
Size of Array integers2 is 10
Array after initialization:
0 0 0 0
0 0 0 0
0 0
Enter 17 integers:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
After input, the Arrays contain:
integers1:
1 2 3 4
5 6 7
integers2:
8 9 10 11
12 13 14 15
16 17
Evaluating: integers1 != integers2
integers1 and integers2 are not equal
Size of Array integers3 is 7
Array after initialization:
1 2 3 4
5 6 7
Assigning integers2 to integers1:
integers1:
8 9 10 11
12 13 14 15
16 17
integers2:
8 9 10 11
12 13 14 15
16 17
Evaluating: integers1 == integers2
integers1 and integers2 are equal
integers1[5] is 13
Assigning 1000 to integers1[5]
integers1:
8 9 10 11
12 1000 14 15
16 17
Attempt to assign 1000 to integers1[15]
An exception occurred: Subscript out of range
1 // Fig. 10.10: Array.h
2 // Array class definition with overloaded operators.
3 #ifndef ARRAY_H
4 #define ARRAY_H
5
6 #include <iostream>
7
8 class Array
9 {
10 friend std::ostream &operator<<( std::ostream &, const Array & );
11 friend std::istream &operator>>( std::istream &, Array & );
12
13 public:
14 explicit Array( int = 10 ); // default constructor
15 Array( const Array & ); // copy constructor
16 ~Array(); // destructor
17 size_t getSize() const; // return size
18
19 const Array &operator=( const Array & ); // assignment operator
20 bool operator==( const Array & ) const; // equality operator
21
22 // inequality operator; returns opposite of == operator
23 bool operator!=( const Array &right ) const
24 {
25 return ! ( *this == right ); // invokes Array::operator==
26 } // end function operator!=
27
28 // subscript operator for non-const objects returns modifiable lvalue
29 int &operator[]( int );
30
31 // subscript operator for const objects returns rvalue
32 int operator[]( int ) const;
33 private:
34 size_t size; // pointer-based array size
35 int *ptr; // pointer to first element of pointer-based array
36 }; // end class Array
37
38 #endif
1 // Fig. 10.11: Array.cpp
2 // Array class member- and friend-function definitions.
3 #include <iostream>
4 #include <iomanip>
5 #include <stdexcept>
6
7 #include "Array.h" // Array class definition
8 using namespace std;
9
10 // default constructor for class Array (default size 10)
11 Array::Array( int arraySize )
12 : size( arraySize > 0 ? arraySize :
13 throw invalid_argument( "Array size must be greater than 0" ) ),
14 ptr( new int[ size ] )
15 {
16 for ( size_t i = 0; i < size; ++i )
17 ptr[ i ] = 0; // set pointer-based array element
18 } // end Array default constructor
19
20 // copy constructor for class Array;
21 // must receive a reference to an Array
22 Array::Array( const Array &arrayToCopy )
23 : size( arrayToCopy.size ),
24 ptr( new int[ size ] )
25 {
26 for ( size_t i = 0; i < size; ++i )
27 ptr[ i ] = arrayToCopy.ptr[ i ]; // copy into object
28 } // end Array copy constructor
29
30 // destructor for class Array
31 Array::~Array()
32 {
33 delete [] ptr; // release pointer-based array space
34 } // end destructor
35
36 // return number of elements of Array
37 size_t Array::getSize() const
38 {
39 return size; // number of elements in Array
40 } // end function getSize
41
42 // overloaded assignment operator;
43 // const return avoids: ( a1 = a2 ) = a3
44 const Array &Array::operator=( const Array &right )
45 {
46 if ( &right != this ) // avoid self-assignment
47 {
48 // for Arrays of different sizes, deallocate original
49 // left-side Array, then allocate new left-side Array
50 if ( size != right.size )
51 {
52 delete [] ptr; // release space
53 size = right.size; // resize this object
54 ptr = new int[ size ]; // create space for Array copy
55 } // end inner if
56
57 for ( size_t i = 0; i < size; ++i )
58 ptr[ i ] = right.ptr[ i ]; // copy array into object
59 } // end outer if
60
61 return *this; // enables x = y = z, for example
62 } // end function operator=
63
64 // determine if two Arrays are equal and
65 // return true, otherwise return false
66 bool Array::operator==( const Array &right ) const
67 {
68 if ( size != right.size )
69 return false; // arrays of different number of elements
70
71 for ( size_t i = 0; i < size; ++i )
72 if ( ptr[ i ] != right.ptr[ i ] )
73 return false; // Array contents are not equal
74
75 return true; // Arrays are equal
76 } // end function operator==
77
78 // overloaded subscript operator for non-const Arrays;
79 // reference return creates a modifiable lvalue
80 int &Array::operator[]( int subscript )
81 {
82 // check for subscript out-of-range error
83 if ( subscript < 0 || subscript >= size )
84 throw out_of_range( "Subscript out of range" );
85
86 return ptr[ subscript ]; // reference return
87 } // end function operator[]
88
89 // overloaded subscript operator for const Arrays
90 // const reference return creates an rvalue
91 int Array::operator[]( int subscript ) const
92 {
93 // check for subscript out-of-range error
94 if ( subscript < 0 || subscript >= size )
95 throw out_of_range( "Subscript out of range" );
96
97 return ptr[ subscript ]; // returns copy of this element
98 } // end function operator[]
99
100 // overloaded input operator for class Array;
101 // inputs values for entire Array
102 istream &operator>>( istream &input, Array &a )
103 {
104 for ( size_t i = 0; i < a.size; ++i )
105 input >> a.ptr[ i ];
106
107 return input; // enables cin >> x >> y;
108 } // end function
109
110 // overloaded output operator for class Array
111 ostream &operator<<( ostream &output, const Array &a )
112 {
113 // output private ptr-based array
114 for ( size_t i = 0; i < a.size; ++i )
115 {
116 output << setw( 12 ) << a.ptr[ i ];
117
118 if ( ( i + 1 ) % 4 == 0 ) // 4 numbers per row of output
119 output << endl;
120 } // end for
121
122 if ( a.size % 4 != 0 ) // end last line of output
123 output << endl;
124
125 return output; // enables cout << x << y;
126 } // end function operator<<
The program begins by instantiating two objects of class Array
—integers1
(Fig. 10.9, line 10) with seven elements, and integers2
(line 11) with the default Array
size—10 elements (specified by the Array
default constructor’s prototype in Fig. 10.10, line 14). Lines 14–16 in Fig. 10.9 use member function getSize
to determine the size of integers1
then output integers1
’s contents, using the Array
overloaded stream insertion operator. The sample output confirms that the Array
elements were set correctly to zeros by the constructor. Next, lines 19–21 output the size of Array integers2
then output integers2
’s contents, using the Array
overloaded stream insertion operator.
Line 24 prompts the user to input 17 integers. Line 25 uses the Array
overloaded stream extraction operator to read the first seven values into integers1
and the remaining 10 values into integers2
. Lines 27–29 output the two arrays with the overloaded Array
stream insertion operator to confirm that the input was performed correctly.
Line 34 tests the overloaded inequality operator by evaluating the condition
integers1 != integers2
The program output shows that the Array
s are not equal.
Line 39 instantiates a third Array
called integers3
and initializes it with a copy of Array integers1
. This invokes class Array
’s copy constructor to copy the elements of integers1
into integers3
. We discuss the details of the copy constructor shortly. The copy constructor can also be invoked by writing line 39 as follows:
Array integers3 = integers1;
The equal sign in the preceding statement is not the assignment operator. When an equal sign appears in the declaration of an object, it invokes a constructor for that object. This form can be used to pass only a single argument to a constructor—specifically, the value on the right side of the =
symbol.
Lines 41–43 output the size of integers3
then output integers3
’s contents, using the Array
overloaded stream insertion operator to confirm that integers3
’s elements were set correctly by the copy constructor.
Line 47 tests the overloaded assignment operator (=
) by assigning integers2
to integers1
. Lines 49–50 display both Array
objects’ contents to confirm that the assignment was successful. Array integers1
originally held 7 integers, but was resized to hold a copy of the 10 elements in integers2
. As we’ll see, the overloaded assignment operator performs this resizing operation in a manner that’s transparent to the client code.
Line 55 uses the overloaded equality operator (==
) to confirm that objects integers1
and integers2
are indeed identical after the assignment in line 47.
Line 59 uses the overloaded subscript operator to refer to integers1[5]
—an in-range element of integers1
. This subscripted name is used as an rvalue to print the value stored in integers1[5]
. Line 63 uses integers1[5]
as a modifiable lvalue on the left side of an assignment statement to assign a new value, 1000
, to element 5
of integers1
. We’ll see that operator[]
returns a reference to use as the modifiable lvalue after the operator confirms that 5
is a valid subscript for integers1
.
Line 70 attempts to assign the value 1000
to integers1[15]
—an out-of-range element. In this example, operator[]
determines that the subscript is out of range and throws an out_of_range
exception.
Interestingly, the array subscript operator [] is not restricted for use only with arrays; it also can be used, for example, to select elements from other kinds of container classes, such as string
s and dictionaries. Also, when overloaded operator[]
functions are defined, subscripts no longer have to be integers—characters, strings or even objects of user-defined classes also could be used. In Chapter 15, we discuss the Standard Library map
class that allows string
subscripts.