Разница между object-> function () и object.function () в C ++ - PullRequest
3 голосов
/ 05 июня 2011

Кто-нибудь может объяснить разницу между тем, как что-то делать:

a->height();

и

a.height();

Есть ли на самом деле разница?

Ответы [ 8 ]

6 голосов
/ 05 июня 2011

В первом примере a является указателем на объект, во втором примере это сам объект (или ссылка на объект). На самом низком уровне нет четкой разницы между ними.

5 голосов
/ 05 июня 2011

Это странный вопрос, если предположить, что речь идет о встроенном ->.Это звучит как «какая разница между молотом и яблоком».Обычно вопрос о «разнице» применяется, когда два варианта, по крайней мере, несколько взаимозаменяемы, оба применяются одновременно.Поэтому люди спрашивают о «разнице», чтобы решить, какой вариант использовать.Это не тот случай, здесь.

Нельзя одновременно указывать a->height() и a.height().Только один из двух может быть действительным, в зависимости от типа a.Т.е. у вас нет выбора, какую версию использовать.Первый (с ->) применим, если левая часть является указателем на объект.Второе (с .) применимо только в том случае, если слева находится само значение объекта.Итак, это все, что нужно.

-> - это просто сокращение для комбинации унарных * и ., что означает, что когда a является указателем, a->height() эквивалентно(*a).height().Итак, более разумный вопрос был бы о разнице между a->height() и (*a).height().И ответ: нет никакой разницы (опять же, пока мы рассматриваем встроенный ->)

2 голосов
/ 06 июня 2011

operator->, за которым следует вызов функции, приведет к разыменованию возвращаемого указателя и вызову функции для результирующего объекта. Короче говоря, a->foo() является сокращением для (*a).foo().

Помимо правильного ответа, что a->foo() требует, чтобы a был указателем на класс, определяющий foo, надуманный пример может сказать что-то другое:

* * 1010

В контексте smartpointers и итераторов stl вы часто будете видеть такие виды определения operator->. В этом контексте определение действительно следует указаниям Страуструпа, чтобы не злоупотреблять им из-за чего-то нелогичного, как мой пример, но чтобы сделать определяющий класс пригодным для использования, как если бы он «указывал» на какой-то объект.

2 голосов
/ 06 июня 2011

Если предположить, что a является указателем на некоторый объект, то:

Это:

a->height();

Это просто сокращение для:

(*a).height();

Позволяет вызывать метод через указатель, а не просто объект (или ссылку).
На самом деле вам не нужно использовать версию ->, но когда вы объединяете несколько вызовов в цепочку, становится понятно, почему это полезно.

person->body()->arm(right)->hand()->finger(index)->ring()->activate();

Если вы напишите эту длинную руку, это будет:

(*(*(*(*(*(*person).body()).arm(right)).hand()).finger(index)).ring()).activate();

Трудно соотнести разыменование (*) с указателем, на который он разыменовывается. В то время как первая версия -> вещь слева - это указатель, вещь справа от части объекта после того, как указатель был отменен.

2 голосов
/ 06 июня 2011

Стоит также отметить, что некоторые объекты, такие как интеллектуальные указатели, поддерживают обе нотации.В этом случае первый будет ссылаться на объект, на который указывает указатель, а второй - на сам умный указатель.

2 голосов
/ 05 июня 2011

Это в основном сводится к тому, как вы объявили «а».Если вы сделаете:

SomeClass a;

, то «a» само является объектом, и вы используете «.»для ссылки на его члены.

Если вы сделаете:

SomeClass * a;
a = [some expression that produces a pointer to a SomeClass object];

, тогда «a» - это указатель на объект, а не сам объект.Затем вы используете нотацию "->".

(Есть некоторые потенциальные исключения из вышеприведенных правил, но они не являются чем-то, с чем сталкивается большинство людей.)

0 голосов
/ 11 июня 2013

Все сводится к тому, насколько читаемым вы хотите сам код и как быстро вы хотите, чтобы он был. На самом низком уровне в ассемблере все сводится к толканию / вытягиванию стека. В реальной жизни с быстрыми компьютерами / MCU это не имеет значения. Это стиль программирования, который вы используете. Оба способа хороши, но не смешивайте их. Это может затруднить чтение для других программистов.

0 голосов
/ 06 июня 2011

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

...