Что я могу использовать вместо оператора стрелки `->`?

Ответы:

148

Следующие два выражения эквивалентны:

a->b

(*a).b

(возможна перегрузка оператора, как упоминает Конрад, но это необычно).

Грег Хьюгилл
источник
9
Проблемы с перегрузкой намного менее необычны, чем вы думаете. Не так давно у разработчиков STL не было перегруженного ->оператора для некоторых типов итераторов, поэтому приходилось использовать *.. Многие библиотеки определяют их непоследовательно. Действительно раздражает, когда вы работаете с шаблонами и не знаете точный тип.
Конрад Рудольф
1
вы также можете сделать a[0].bвместо (*a).b. Но это было бы не так правильно.
Sellorio
2
Мальчик, после многих лет программирования на C # возврат к C ++ не только утомителен, но и синтаксис C ++ уродлив и неприятен. После этого хочется принять душ. Программы, написанные на C и C ++, просто способствуют плохому программированию. Apple, до Unix, изо всех сил пыталась сделать язык таким же красивым, как Паскаль.
ATL_DEV 09
@ATL_DEV Я бы сказал, что многие уродливые вещи больше не считаются идиоматическими, но, к сожалению, это не значит, что вы можете позволить себе не знакомиться с ними как практикующий программист на C ++. Кроме того, синтаксически хороший путь часто не является семантически хорошим путем, но он также становится лучше, а не хуже. Но опять же, у меня Стокгольмский синдром C ++.
Тим Сегин
@TimSeguine Если вы когда-нибудь захотите увидеть красивый код, то посмотрите документацию внутри Macintosh. Думаю, они изобрели CamelCase. Очень наглядные имена переменных и элегантно отформатированный код. Им удалось сделать свой более поздний код на C почти таким же великолепным, как и их более ранний код на Паскале.
ATL_DEV 07
70

a->bобычно является синонимом (*a).b. Круглые скобки здесь необходимы из-за силы связывания операторов *и .: *a.bне будет работать, потому что .связывает сильнее и выполняется первым. Таким образом, это эквивалентно *(a.b).

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

Конрад Рудольф
источник
1
К binding strengthвы имеете в виду оператор приоритет? если нет, в чем разница между ними?
вишнупрасантх
1
@Vizkrig Да, эти два термина используются взаимозаменяемо (хотя «приоритет оператора», кажется, встречается гораздо чаще, по крайней мере, в последние годы).
Конрад Рудольф
45

В языке C ++ оператор стрелки ( ->) определяется как синоним разыменования указателя, а затем для .этого адреса используется оператор -оператор .

Например:

Если у вас есть объект anObject, и указатель aPointer:

SomeClass anObject = new SomeClass();
SomeClass *aPointer = &anObject;

Чтобы иметь возможность использовать один из методов объекта, вы разыменовываете указатель и вызываете метод по этому адресу:

(*aPointer).method();

Что можно было бы написать с помощью оператора стрелки:

aPointer->method();

Основная причина существования оператора стрелки заключается в том, что он сокращает типизацию очень распространенной задачи, а также позволяет легко забыть скобки вокруг разыменования указателя. Если вы забыли круглые скобки, оператор. -Оператор будет связывать сильнее, чем * -оператор, и заставит наш пример выполняться как:

*(aPointer.method()); // Not our intention!

В некоторых других ответах также упоминается, что операторы C ++ могут быть перегружены и что это не так часто.

PA
источник
8
new SomeClass()возвращает указатель ( SomeClass *), а не SomeClassобъект. И вы начинаете с объявления, anObjectа потом aPointerиспользуете p.
musiphil
в целом это объяснение теоретически очень уместно, только смена предметов делает его немного запутанным. Но этот процесс лучше описать
Code Man
17

В C ++ 0x оператор получает второе значение, указывающее тип возвращаемого значения функции или лямбда-выражения.

auto f() -> int; // "->" means "returns ..."
Йоханнес Шауб - litb
источник
1
Технически пятнистость там уже не "оператор", или нет?
Мартин Ба
6
@Martin: большинство людей используют слово «оператор» для многих вещей, которые напрямую не используются для вычисления значений. Как для "::" ("оператор области видимости"). Я точно не знаю, какова точка зрения стандарта по этому поводу. В абстрактном смысле можно рассматривать «->» как функциональный оператор, отображающий последовательность типов (параметров) в тип возвращаемого значения, например, оператор haskell, который также записывается «->».
Йоханнес Шауб - лит
6
Я подчиняюсь! :-P
Мартин Ба
2
@ JohannesSchaub-litb: ::фактически является оператором, подобным .или ->, и в стандарте называется «оператором разрешения области видимости».
musiphil
13

Чаще читаю справа налево и зову "в"

foo->bar->baz = qux->croak

будет выглядеть так:

"baz в bar в foo становится квакером в qux"

Тета
источник
1

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

Например, вы можете создать указатель ptr на переменную типа int intVar следующим образом:

int* prt = &intVar;

Затем вы можете использовать для него функцию, такую ​​как foo, только путем разыменования этого указателя - чтобы вызвать функцию для переменной, на которую указывает указатель, а не для числового значения ячейки памяти этой переменной:

(*ptr).foo();

Без круглых скобок компилятор мог бы понять это как *(ptr.foo())из-за приоритета операторов, чего мы не хотим.

На самом деле это то же самое, что вводить

ptr->foo();

Как ->разыменование этого указателя и, таким образом, вызывает функцию foo()для переменной, на которую указывает указатель.

Точно так же мы можем использовать ->для доступа или установки члена класса:

myClass* ptr = &myClassMember;
ptr->myClassVar = 2; 
Tryb Ghost
источник
0

Вы можете использовать -> для определения функции.

auto fun() -> int
{
return 100;
}

Это не лямбда. Это действительно функция. «->» указывает тип возвращаемого значения функции.

Чжан
источник