История: почему мы можем перегрузить -> а нет. оператор? Оба являются членами оператора доступа и имеют одинаковое значение.
Я прочитал некоторые ссылки из
http://www.stroustrup.com/bs_faq2.html#overload-dot
А ТАКЖЕ
Почему оператор может> перегружаться вручную?
Но все же мои сомнения остаются прежними, почему мы можем перегрузить .operator, а не ->?
Это потому, что оператор -> неявно получает ссылку на возвращаемый указатель и, таким образом, делает вызов как цепочку вызовов
struct X {
int foo;
};
struct Y {
X x;
X* operator->() { return &x; }
};
struct Z {
Y y;
Y& operator->() { return y; }
};
Z z;
z->foo = 42; // Works!
z-> foo = 42; Этот вызов преобразуется в ((z.operator ()). Opeartor ()). Operator () и, таким образом, значение foo устанавливается равным 42.
Вопрос: — Если я возьму эту точку, у меня останутся еще две точки,
1) почему нельзя. (Точка) оператор работает таким образом?
2) Что делать, если оператор -> не возвращает ссылку на класс Y? Это будет ошибка компиляции в этом случае?
Я только понял, как работает перегрузка оператора-> после прочтения этот:
Выражение E1-> E2 в точности эквивалентно (* E1) .E2 для встроенных типов. Если задан пользовательский оператор->, оператор-> вызывается снова для значения, которое он возвращает, рекурсивно, пока не будет достигнут оператор->, который возвращает простой указатель. После этого к указателю применяется встроенная семантика.
Чтобы ответить на ваш второй вопрос … давайте снова посмотрим на ваш пример:
struct X { int foo; };
struct Y {
X x;
X* operator->() { return &x; } // returns pointer
};
struct Z {
Y y;
Y& operator->() { return y; } // returns reference
};
Z z;
z->foo = 42; // Works!
Вызов z->
оценивает z.y
, Это не указатель, поэтому рекурсия продолжается: (z.y)->
оценивает &(z.y.x)
, Это указатель, а полученное выражение (&(z.y.x))->
,
Если вы заставите Zs оператор возвращать указатель, рекурсия останавливается на &(z.y)
но Y
не имеет foo
и компилятор будет жаловаться.