тип имя_класса::operator[](int индекс)
{
// ...
}
Оператор "[]" перегружается как бинарный оператор.
Формально параметр индекс необязательно должен иметь тип int, но операторные функции operator[]() обычно используются для обеспечения индексации массивов, поэтому в общем случае в качестве аргумента этой функции передается целочисленное значение.
Предположим, у нас определен объект ob, тогда выражение
ob[3]
преобразуется в следующий вызов операторной функции operator[]():
ob.operator[](3)
Другими словами, значение выражения, заданного в операторе индексации, передается операторной функции operator[]() в качестве явно заданного аргумента. При этом указатель this будет указывать на объект ob, т.е. объект, который генерирует вызов этой функции.
В следующей программе в классе atype объявляется массив для хранения трех int-значений. Его конструктор инициализирует каждый член этого массива. Перегруженная операторная функция operator[]() возвращает значение элемента, заданного его параметром.
// Перегрузка оператора индексации массивов
#include <iostream>
using namespace std;
const int SIZE = 3;
class atype {
int a[SIZE];
public:
atype() {
register int i;
for(i=0; i<SIZE; i++) a[i] = i;
}
int operator[](int i) {return a[i];}
};
int main()
{
atype ob;
cout << ob[2]; // отображает число 2
return 0;
}
Здесь функция operator[]() возвращает значение i-го элемента массива a. Таким образом, выражение ob[2] возвращает число 2, которое отображается инструкцией cout. Инициализация массива a с помощью конструктора (в этой и следующей программах) выполняется лишь в иллюстративных целях.
Можно разработать операторную функцию operator[]() так, чтобы оператор "[]" можно было использовать как слева, так и справа от оператора присваивания. Для этого достаточно указать, что значение, возвращаемое операторной функцией operator[](), является ссылкой. Эта возможность демонстрируется в следующей программе.
// Возврат ссылки из операторной функции operator()[].
#include <iostream>
using namespace std;
const int SIZE = 3;
class atype {
int a[SIZE];
public:
atype() {
register int i;
for(i=0; i<SIZE; i++) a[i] = i;
}
int &operator[](int i) {return a[i];}
};
int main()
{
atype ob;
cout << ob[2]; // Отображается число 2.
cout <<" ";
ob[2] = 25; // Оператор "[]" стоит слева от оператора "=".
cout << ob[2]; // Теперь отображается число 25.
return 0;
}
При выполнении эта программа генерирует такие результаты.
2 25
Поскольку функция operator[]() теперь возвращает ссылку на элемент массива, индексируемый параметром i, оператор "[]" можно использовать слева от оператора присваивания, что позволит модифицировать любой элемент массива. (Конечно же, его по-прежнему можно использовать и справа от оператора присваивания.)
Одно из достоинств перегрузки оператора "[]" состоит в том, что с его помощью мы можем обеспечить средство реализации безопасной индексации массивов. Как вы знаете, в C++ возможен выход за границы массива во время выполнения программы без Соответствующего уведомления (т.е. без генерирования сообщения о динамической ошибке). Но если создать класс, который содержит массив, и разрешить доступ к этому массиву только через перегруженный оператор индексации "[]", то возможен перехват индекса, значение которого вышло за дозволенные пределы. Например, следующая программа (в основу которой положен код предыдущей) оснащена средством контроля попадания в допустимый интервал.