Операция индексирования обязана возвращать ссылку, так как выражение имя [индекс] может стоять как справа, так и слева от знака присваивания:
TString t = "Привет от RR строки!"; t[12] = t[6];
Если выражение имя [индекс] стоит слева от знака присваивания, то изменяется текущий объект (так же, как и в операциях с присваиванием).
Кроме того, обычно реализуют два метода: константный и неконстантный. Неконстантный метод работает, когда выражение имя [индекс] стоит слева от знака присваивания. Константный метод вызывается, когда выражение имя [индекс] используется для доступа к символам константы-строки (объявленной явно или передаваемой как параметр по константной ссылке).
Наша операция, естественно, должна проверять правильность задания индекса. Так как тип индекса — byte, являющийся переопределенным типом unsigned char, то фактически надо проверять, не равен ли индекс 255, так как ни меньше нуля, ни больше 255 значение быть не может. Правда неясно, что делать, если заданный индекс все-таки равен 255. Наилучшим решением было бы прекратить выполнение операции и как-то сообщить об этом в вызывающую программу. Однако как и для конструкторов, это можно сделать только с помощью механизма обработки исключений — другим способом нам это сделать не удастся. Например, не получится возвращать код завершения, сигнализирующий об ошибке, так как операция должна возвращать ссылку, а не значение. Лишний параметр, в котором можно было бы передать код ошибки, мы тоже использовать не можем, поскольку никаких лишних параметров не допускается — операция индексирования является бинарной и должна иметь всего два аргумента. Один из них — текущий объект, второй — индексное выражение в квадратных скобках.
Поэтому до изучения механизма исключений придется реализовывать константный и неконстантный методы по-разному. Так как константный метод не изменяет содержимое полей класса, то в константном методе можно возвратить ссылку на последний нулевой элемент массива символов — это и будет служить признаком ошибки. В неконстантном методе так поступать нельзя: если операция применяется слева от знака присваивания, то, возвращая ссылку на завершающий элемент, мы разрешаем его изменять. Таким образом, мы можем «лишиться» завершающего нуля, и работа многих методов будет нарушена. Поэтому пока будем завершать этот метод аварийно.
ВНИМАНИЕ
Это — не лучшее решение. В профессиональном программировании аварийное завершение программы выполняется только в безвыходной ситуации. Мы пересмотрим это решение позднее после изучения механизма исключений.
Если вы достаточно долго работаете программистом и скопили некоторые деньги, тогда можно купить катер. Продажа катеров б у тут недорого.
С учетом этих соображений реализация выглядит так, как показано в листинге 4.9.
Листинг 4.9. Реализация операции индексирования
char& operator[](const byte &index)
{ if (index<255) return s[index]; // нормальная работа
else abort(); // аварийное завершение
}
const char& operator[](const byte &index) const
{ if (index<255) return s[index]; // правильный индекс
else return s[255]; // неправильный индекс
Функции-операции достаточнолросты, поэтому мы реализовали их как подставляемые непосредственно в классе. |