2014-08-29 2 views
4

Я изучаю, как перегружать «->», и в документации говорится, что: «operator-> вызывается снова по значению, которое он возвращает, рекурсивно, >, который возвращает простой указатель. После этого к этому указателю применяется встроенная семантика. "перегрузка «->» (членский доступ) рекурсивно

Хотя понятно, что в документации говорится, что перегруженный «->» класс может использовать сам «специальный указатель», имеющий перегруженный «->», который может дать «специальный указатель» и т. Д. И т. Д. пока не будет найден «простой указатель», я не могу найти пример его реального использования (если только он не используется для поиска связанного списка последнего элемента).

Может ли кто-нибудь объяснить, что такое retionale за кулисами (поскольку эта возможность не предоставляется «простым указателям», поэтому я не вижу причин, чтобы предоставить ей «специальные указатели»).

Пример использования реального мира также может помочь, поскольку, вероятно, мне не хватает модели, где можно применять поведение.

С другой стороны, может возникнуть необходимость избежать такого поведения, как это можно сделать?

+0

Не могли бы вы определить «обычный указатель» и «специальный указатель» – CoffeeandCode

+0

Я посмотрел на то, что shared_ptr есть, но где рекурсия? –

+1

«простой указатель» - это «обычный указатель» на C++. –

ответ

2

Я не могу найти пример его реального использования (если только он не используется, чтобы найти связанный список последнего элемента).

Я думаю, вы не понимаете, что он делает. Он не используется для разыменования элемента списка и продолжения разыменования следующего элемента. Каждый раз, когда вы вызываете operator->, вы должны вернуть другого типа, дело в том, что если этот второй тип также имеет номер operator->, он будет вызываться, что может снова вернуть другой тип. Представьте себе, что быть как x->->->i не x->next->next->next, если это помогает

В качестве примера реального мира использования может помочь тоже, как, вероятно, я пропускаю модель, где применить поведение.

Это может быть полезно для модели Execute Around Pointer.

На противоположной стороне может возникнуть необходимость избегать такого поведения, как это можно сделать?

вызова оператор явно:

auto x = p.operator->(); 
7

Ну, оператор -> работает под особыми обстоятельствами.

Можно назвать его псевдо-двоичным оператором. В соответствии с его естественным синтаксисом pointer->member он принимает два операнда: обычный операнд времени выполнения с левой стороны и довольно «странный» член-член операнд с правой стороны. «Странность» второго операнда коренится в том, что язык C++ не имеет понятной пользователю концепции для представления таких операндов. В языке нет ничего, что могло бы выразить имя участника в качестве операнда. Невозможно «передать» имя члена через код в пользовательскую реализацию. Имя члена - это объект компиляции, удаленно подобный константным выражениям в этом отношении, но никакое постоянное выражение в C++ не может указывать элементы. (Есть выражения для указателей-к-членам, но не для самих членов).

Это создает довольно очевидные трудности при указании поведения перегруженного оператора ->: как мы подключаем то, что было указано в правой части -> (то есть имя участника), к коду, написанному пользователем? Это невозможно сделать напрямую. Единственный выход из этой ситуации - косвенно сделать это: заставить пользователя направить пользовательские функции перегруженного оператора -> в функциональность какого-либо существующего встроенного оператора. Встроенный оператор может обрабатывать имена участников, естественно, благодаря своим основным языковым возможностям.

В данном конкретном случае у нас есть только два кандидата для перенаправления функций перегруженного -> на: встроенный -> и встроенный .. Логично, что для этой роли был выбран встроенный ->. Это создало интересный побочный эффект: возможность писать «цепные» (рекурсивные) последовательности перегруженных операторов -> (разворачиваются неявно компилятором) и даже бесконечно рекурсивные последовательности (которые плохо сформированы).

Неофициально, каждый раз, когда вы используете интеллектуальный указатель, вы делаете реальное использование этих «рекурсивных» свойств перегруженного оператора ->. Если у вас есть умный указатель sptr, который указывает на объект класса с членом member, синтаксис доступа к членству остается совершенно естественным, например. sptr->member.Вам не обязательно делать это как sptr->->member или sptr->.member именно из-за неявных «рекурсивных» свойств перегруженных ->.

Обратите внимание, что это рекурсивное поведение применяется только тогда, когда вы используете оператор синтаксис для вызова перегруженного -> оператора, т.е. синтаксиса object->member. Однако вы также можете использовать регулярный синтаксис вызова функции-члена, чтобы вызвать перегруженный ->, например. object.operator ->(). В этом случае вызов выполняется как обычный вызов функции и не выполняется рекурсивное приложение ->. Это единственный способ избежать рекурсивного поведения. Если вы реализуете перегруженный оператор ->, тип возврата которого не поддерживает дальнейшие приложения оператора -> (например, вы можете определить перегруженный ->, который возвращает int), то object.operator ->() будет единственным способом вызвать вашу перегруженную реализацию. Любые попытки использовать синтаксис object->member будут плохо сформированы.

+0

Есть указатели на членов, так что понятие «член» доступно для программиста. –

+0

Но вопрос об рекурсии !!! –

+2

@GeorgeKourtis, но когда правый операнд является указателем на члена, вы должны сказать 'x -> * pmf' не' x-> name', поэтому он недоступен с помощью 'operator->' –

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