Программирование на C и C++

Онлайн справочник программиста на C и C++

Перегрузка []

Кроме нескольких вышеперечисленных операторов, можно перегрузить и любые другие операторы С++. Большей частью требуется перегружать стандартные операторы, такие как арифметические, логические или операторы отношения. Тем не менее имеется один достаточно экзотичный опера­тор, который бывает полезно перегружать: []. В С++ оператор [] при перегрузке рассматривается как бинарный оператор. Его следует перегружать с помощью функции-члена. Нельзя использовать дружественную функцию. Общая форма функции-оператора operator[]() имеет следующий вид:

тип имя_класса::оpеrator[](int i)
{
// ...
}

Параметр не обязан иметь тип int, но поскольку функция operator[]() обычно используется для индексации массива, то в таком качестве обычно используется целое значение.
Для заданного объекта О выражение

О [3]

преобразуется в вызов функции operator[]():

operator[](3)

В таком случае значение индекса передается функции operator[]() в качестве явного параметра. Указатель this указывает на объект О, тот самый, который вызывает функцию.

В следующей программе класс atype содержит массив из трех переменных целого типа. Конст­руктор инициализирует каждый элемент массива заданным значением. Перегруженная функция-оператор operator[]() возвращает величину элемента массива, определяемого индексом, передава­емым в качестве параметра.

#include <iostream.h>
class atype {
int a[3];
public:
atype (int i, int j, int k) {
a[0] = i;
a[1] = j;
a[2] = k;
}
int operator[] (int i) { return a[i]; }
};
int main()
{
atype ob(1, 2, 3);
cout << ob[1]; // выводит 2
return 0;
}

Можно создать функцию-оператор operator[]() таким образом, чтобы оператор [] можно было использовать как с левой, так и с правой стороны оператора присваивания. Для этого достаточ­но в качестве возвращаемой величины для operator[]() задать ссылку. Сказанное проиллюстриро­вано в следующей программе:

#include <iostream.h>
class atype {
int a[3];
public:
atype (int i, int j, int k) {
a[0] = i;
a[1] = j;
a[2] = k;
}
int &operator[] (int i) { return a[i]; }
};
int main()
{
atype ob(1, 2, 3);
cout << ob[1]; // выводит 2
cout << " ";
ob[1] = 25; // [] слева от =
cout << ob[1]; // выводит 25
return 0;
}

Поскольку operator[]() возвращает ссылку на элемент массива, отвечающий индексу i, то он может быть использован с левой стороны операции присваивания для модификации элемента массива. Разумеется, этот оператор может быть использован и с правой стороны оператора присваивания.

Как известно, в С++ во время выполнения программы можно выйти за пределы массива, и при этом не будет выдаваться сообщение об ошибке. Одним из достоинств перегрузки оператора [] служит то, что с его помощью можно предотвратить подобные эффекты.

Если создается класс, содержащий массив, и разрешен доступ к этому массиву только через перегруженный оператор [], то можно перехватывать значение, содержащее величину индекса за пределами допустимых значений. Например, следующая программа осуществляет проверку на принадлежность значений допустимой области:

// пример безопасного массива
#include <iostream.h>
#include <stdlib.h>
class atype {
int a[3];
public:
atype (int i, int j, int k) {
a[0] = i;
a[1] = j;
a[2] = k;
}
int &operator[] (int i);
};
// проверка диапазона для atype.
int &atype::operator [] (int i)
{
if (i<0 | | i>2) {
cout << "Boundary Error\n";
exit (1);
}
return a[i];
}
int main()
{
atype ob(1, 2, 3);
cout << ob[1]; // выводит 2
cout << " ";
ob[1] = 25; // [] слева
cout << ob[1]; // выводит 25
ob[3] = 44; // генерируется ошибка времени выполнения, поскольку 3 выходит за допустимые пределы
return 0;
}

При выполнении инструкции

ob[3] = 44;

оператор перехватывает ошибку выхода за допустимую область и программа заканчивает свою работу прежде, чем сможет нанести ущерб системе.