10.10.1. Using the Array Class

The program of Figs. 10.910.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


Fig. 10.9. Array class test program.


 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


Fig. 10.10. Array class definition with overloaded operators.


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


Fig. 10.11. Array class member- and friend-function definitions.

Creating Arrays, Outputting Their Size and Displaying Their Contents

The program begins by instantiating two objects of class Arrayintegers1 (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.

Using the Overloaded Stream Insertion Operator to Fill an Array

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.

Using the Overloaded Inequality Operator

Line 34 tests the overloaded inequality operator by evaluating the condition

integers1 != integers2

The program output shows that the Arrays are not equal.

Initializing a New Array with a Copy of an Existing Array’s Contents

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.

Using the Overloaded Assignment Operator

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.

Using the Overloaded Equality Operator

Line 55 uses the overloaded equality operator (==) to confirm that objects integers1 and integers2 are indeed identical after the assignment in line 47.

Using the Overloaded Subscript Operator

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

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset