14.7. Операторы доступа к членам
Операторы обращения к значению (*) и стрелка (->) обычно используются в классах, представляющих итераторы, и в классах интеллектуального указателя (см. раздел 12.1). Вполне логично добавить эти операторы в класс StrBlobPtr:
class StrBlobPtr {
public:
std::string& operator*() const {
auto p = check(curr, "dereference past end");
return (*p)[curr]; // (*p) - вектор, на который указывает этот
// объект
}
std::string* operator->() const {
// передать реальную работу оператору обращения к значению
return &this->operator*();
}
// другие члены как прежде
};
Оператор обращения к значению проверяет принадлежность curr диапазону, и если это так, то возвращает ссылку на элемент, обозначенный значением curr. Оператор стрелки не делает ничего сам, он вызывает оператор обращения к значению и возвращает адрес возвращенного им элемента.

Следует заметить, что эти операторы определены как константные члены. В отличие от операторов инкремента и декремента, выборка элемента никак не изменяет состояния объекта класса StrBlobPtr. Обратите также внимание на то, что эти операторы возвращают ссылку или указатель на неконстантную строку. Причина этого в том, что объект класса StrBlobPtr, как известно, может быть связан только с неконстантным объектом класса StrBlob (см. раздел 12.1.6).
Эти операторы можно использовать таким же способом, которым используются соответствующие операторы с указателями и итераторами вектора:
StrBlob a1 = {"hi", "bye", "now"};
StrBlobPtr p(a1); // p указывает на вектор в a1
*p = "okay"; // присвоить первый элемент a1
cout << p->size() << endl; // выводит 4, размер первого элемента в a1
cout << (*p).size() << endl; // эквивалент p->size()
Ограничения на возвращаемое значение оператора стрелки
Подобно большинству других операторов (хотя это и плохая идея), оператор operator* можно определить как выполняющий некие действия по своему усмотрению. Таким образом, оператор operator* можно определить как возвращающий, например, фиксированное значение, скажем, 42, или выводящий содержимое объекта, к которому он применен, или что то еще. Но для перегруженного оператора стрелки это не так. Оператор стрелки никогда не изменяет своего фундаментального назначения: доступа к члену класса. При перегрузке оператора стрелки можно изменить объект, из которого стрелка выбирает определенный член, но нельзя изменить тот факт, что она выбирает член класса.
В коде point->mem часть point должна быть указателем на объект класса или объектом класса с перегруженным оператором operator->. В зависимости от типа части point код point->mem может быть эквивалентен следующему:
(*point).mem; // point - указатель встроенного типа
point.operator()->mem; // point - объект типа класса
В противном случае код ошибочен. Таким образом, код point->mem выполняется следующим образом.
1. Если point — указатель, то применение встроенного оператора стрелки означает эквивалент выражения (*point).mem. Указатель обращается к значению члена класса и выбирает его из объекта. Если у типа, на объект которого указывает point, нет члена по имени mem, то этот код ошибочен.
2. Если point — объект класса, в котором определен оператор operator->, то результат вызова point.operator->() используется для выбора члена mem. Если результат является указателем, то для него выполняется этап 1. Если результат является объектом, класс которого сам обладает перегруженным оператором operator->(), то с этим объектом повторяется данный этап. Процесс продолжается до тех пор, пока не будет возвращен указатель на объект с означенным членом или некое другое значение, означающее ошибочность кода.
Упражнения раздела 14.7
Упражнение 14.30. Добавьте операторы обращения к значению и стрелки в класс StrBlobPtr и класс ConstStrBlobPtr из упражнения 12.22 раздела 12.1.6. Обратите внимание, что операторы класса ConstStrBlobPtr должны возвращать константные ссылки, поскольку переменная-член data класса ConstStrBlobPtr указывает на константный вектор.
Упражнение 14.31. В классе StrBlobPtr не определен конструктор копий, оператор присвоения и деструктор. Почему?
Упражнение 14.32. Определите класс, содержащий указатель на класс StrBlobPtr. Определите перегруженный оператор стрелки для этого класса.