Overloading Operators for an Array Class

The array mechanism that is built into C is very primitive; it is essentially an alternate syntax for using pointers. An array doesn't store its size, and there is no way to keep someone from accidentally indexing past the end of the array. In C++, you can define a much safer and more powerful array type using a class. To make such a class look more like an array, you can overload the subscript operator ([]).

The following example defines the IntArray class, where each object contains an array of integers. This class overloads the [] operator to perform range checking.

// Overloaded [] operator

#include <iostream.h>

#include <string.h>

class IntArray

{

public:

IntArray( int len );

int getLength() const;

int &operator[]( int index );

~IntArray();

private:

int length;

int *aray;

};

// ------------ Constructor

IntArray::IntArray( int len )

{

if( len > 0 )

{

length = len;

aray = new int[len];

// initialize contents of array to zero

memset( aray, 0, sizeof( int ) * len );

}

else

{

length = 0;

aray = 0;

}

}

// ------------ Function to return length

inline int IntArray::getLength() const

{

return length;

}

// ------------ Overloaded subscript operator

// Returns a reference

int &IntArray::operator[]( int index )

{

static int dummy = 0;

if( (index = 0) &&

(index < length) )

return aray[index];

else

{

cout << "Error: index out of range.\n";

return dummy;

}

}

// ------------ Destructor

IntArray::~IntArray()

{

delete aray;

}

void main()

{

IntArray numbers( 10 );

int i;

for( i = 0; i < 10; i++ )

numbers[i] = i; // Use numbers[i] as lvalue

for( i = 0; i < 10; i++ )

cout << numbers[i] << '\n';

}

This program first declares an IntArray object that can hold ten integers. Then it assigns a value to each element in the array. Notice that the array expression appears on the left side of the assignment. This is legal because the operator[]] function returns a reference to an integer. This means the expression numbers[i] acts as a alias for an element in the private array, so it can be the recipient of an assignment statement. In this situation, returning a reference is not simply more efficient, but is necessary.

The operator[] function checks whether the specified index value is within range or not. If it is, the function returns a reference to the corresponding element in the private array. If it isn't, the function prints out an error message and returns a reference to a static integer. This prevents out-of-range array references from overwriting other regions of memory, though it will probably cause unexpected program behavior. As an alternative, you could have the operator[] function exit the program when it receives an out-of-range index value.

As it is currently implemented, the index values for an IntArray object of size n range from 0 to n-1, but that is not a requirement. You can use any value you want for the bounds of the array, or even have the bounds specified when an object is declared.

The IntArray class has a number of advantages over conventional arrays in C. The size of an IntArray doesn't have to be a constant; you can determine the size at run time without having to use new and delete. An IntArray object also stores its size, so you can pass one to a function without having to pass the size separately. One possible enhancement is to make IntArrays resizeable, so that you could expand one if it became full.

You can also overload operator[] for classes that aren't implemented as arrays. For example, you could write a linked list class and allow users to use array notation to access the nodes in the list. You can even use values other than integers for indexing. For example, consider the following prototype:

int &operator[]( const char *key );

This operator[] function takes a string as an index. This permits expressions like the following:

salary["John Smith"] = 25000;

You could use the string as a key for searching through a data structure, which could be an array or a linked list or something else. Since it would be difficult to iterate through such a class using a for loop, this class would probably benefit from having an iterator implemented with a friend class, as mentioned in Chapter 6.

The operator[] function takes only one parameter. You cannot give it multiple parameters to simulate a multidimensional array. For example:

int &SquareArray::operator[]( int row, int col ); // Error

You can, however, overload the () operator, which can take an arbitrary number of parameters. For example:

int &SquareArray::operator()( int row, int col );

This allows statements like the following:

SquareArray myArray;

myArray( 3, 4 ) = 1;

Note that this is not standard array notation in C, so it may be confusing for other programmers reading your code.

The operator[] function cannot be defined as a friend function. It must be a nonstatic member function.