2016-03-02 2 views
3

Я смотрел на стандарт C++ относительно базового элемента операторы (унарный * Разыменование оператор, оператор аксессор -> член), а также многие другие связанные вопросы:C++ доступ к члену/Косвенная оператор эквивалентности

C++ - Difference between (*). and ->?

ptr->hello(); /* VERSUS */ (*ptr).hello();

C++ pointers difference between * and ->

Я видел, что большинство ответов говорится, что p->m является синтаксическим сахаром для (*p).m, как это определено в стандарте C++ (5.2.5, пункт 2):

Выражение E1->E2 преобразуется в эквивалентной форме (*(E1)).E2

Многие комментарии также отметил, что из-за operator* и operator-> являются перегружаемыми в классах, они должны быть перегружены равномерно для обеспечения согласованного поведения.

Эти утверждения, кажется, противоречат друг другу: если (в соответствии со стандартом) E1->E2 преобразуется в эквивалентную форму (*(E1)).E2, то, что было бы целью перегрузки operator-> (как это разрешено стандартом)?

Проще говоря, эти две части стандарта в конфликте, или я не понимаю стандарт?
Преобразование эквивалентности E1->E2 в (*(E1)).E2 распространяется на все полные типы или только на встроенные?

+1

См. Пункт 3 раздела 5, «Пункт 5 определяет эффекты операторов при применении к типам, для которых они не были перегружены». –

ответ

5

Преобразование из E1 -> E2 в (*(E1)).E2 относится только к типам необработанных указателей. Для типов классов E1 -> E2 оценивает (E1).operator->().E2, что потенциально может рекурсивно расширять еще больше копий operator->, если тип возврата operator-> сам по себе не является типом указателя. Вы можете увидеть это, создав тип, поддерживающий operator*, но не operator-> и пытающийся использовать на нем оператор стрелки; вы получите сообщение об ошибке operator-> не определено.

В качестве продолжения обычно используется operator -> с точки зрения operator * таким образом, чтобы семантика -> соответствовала семантике указателей. Вы часто видите такие вещи, как это:

PointerType ClassType::operator->() const { 
    return &**this; 
} 

Это выражение интерпретируется как

&(*(*this)), 

означает «взять этот объект (*this), разыменования его (*(*this)), и получить адрес, что вы найдете (&(*(*this)).). " Теперь, если вы используете правило, что E1 -> E2 должно быть эквивалентно (*(E1)).E2, вы можете видеть, что в итоге получаете что-то эквивалентное.

+0

Это отличное объяснение! Я никогда не понимал разрешение исходного указателя перед преобразованием эквивалентного выражения. Пример был очень полезной иллюстрацией. – callyalater

Смежные вопросы