我可以使用什么代替箭头运算符“->”?

137
箭头运算符(->)是什么意思?它的同义词是什么?
7个回答

179
以下两个表达式意思相同:
a->b

(*a).b

(如Konrad所提到的,这取决于操作符重载,但这很不寻常).


11
重载问题比你想象的要常见得多。不久之前,STL实现者对于某些迭代器类型没有重载 -> 运算符,因此必须使用 *. 运算符。许多库定义它们的方式不一致,在使用模板并且不知道精确类型时会变得非常烦人。 - Konrad Rudolph
2
你也可以使用a[0].b代替(*a).b。但这样不够结构化。 - Sellorio
6
多年使用C#编程后,回到C++编程不仅认知负担重,而且C++语法非常丑陋难看。使用它会让我感觉需要洗个澡。用C和C++编写的程序更容易产生糟糕的编程习惯。在Unix之前,苹果公司曾经努力将该语言美化得像Pascal一样。 - ATL_DEV
1
@ATL_DEV 我认为很多丑陋的东西不再被视为惯用语了,但不幸的是,作为一名实践的C++程序员,你不能不熟悉它。另外,语法上漂亮的路径通常不是语义上漂亮的路径,但这也越来越好了而不是更糟。但我又有C++斯德哥尔摩综合症。 - Tim Seguine
2
@TimSeguine 如果你想看到漂亮的代码,那就看看Macintosh内部的文档吧。我认为他们发明了驼峰命名法。非常描述性的变量名和优雅格式化的代码。他们设法使他们后来的C代码几乎与早期的Pascal代码一样美丽。 - ATL_DEV

74

a->b 通常是 (*a).b 的同义词。这里的括号是必须的,因为操作符 *. 的结合强度不同: *a.b 不会生效,因为 . 结合更强,会先执行。因此,这等效于 *(a.b)

注意不要过载:由于 ->* 都可以被重载,它们的意义可能会有很大差别。


2
你所说的“binding strength”是指运算符优先级吗?如果不是,那么它们之间有什么区别? - vishless
2
@Vizkrig 是的,这两个术语可以互换使用(尽管“运算符优先级”似乎在近年来更为常见)。 - Konrad Rudolph

47

C++语言将箭头操作符(->)定义为对指针进行解引用并使用.操作符在该地址上进行操作的同义词。

例如:

如果您有一个对象anObject和一个指针aPointer

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

为了使用对象的方法,您需要解引用指针并对该地址进行方法调用:
(*aPointer).method();

这可以使用箭头操作符来写:

aPointer->method();

箭头运算符存在的主要原因是它缩短了一个非常常见的任务的输入,而且在解引用指针时很容易忘记括号。如果你忘记了括号,那么 .-运算符会比 *-运算符更强地绑定,并使我们的示例执行为:
*(aPointer.method()); // Not our intention!

一些其他答案也提到了C++运算符可以重载,但这并不常见。

8
new SomeClass() 返回一个指针(SomeClass *),而不是 SomeClass 对象。你开始声明了 anObjectaPointer,但后面却使用了 p - musiphil
总的来说,这个解释在理论上非常恰当,只是对象的变化使得它有些复杂。但是过程描述得更好了。 - Code Man

19
在C ++0x中,运算符获得了第二个意义,表示函数或lambda表达式的返回类型。
auto f() -> int; // "->" means "returns ..."

1
从技术上讲,那里不再是一个“操作符”,难道不是吗? - Martin Ba
6
大多数人使用“operator”一词来表示许多与计算值无直接关系的事物,比如“::”(“作用域运算符”)。我不确定标准对此有何看法。抽象地说,人们可以将“->”视为一个函数运算符,将一系列类型(参数)映射到一个返回类型,就像Haskell运算符一样,它也被写成“->”。 - Johannes Schaub - litb
2
@JohannesSchaub-litb:::实际上是一个操作符,就像.->一样,在标准中被称为“作用域解析运算符”。 - musiphil

13

我大多数情况下从右向左阅读并称之为“in”

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

"foo 中的 bar 中的 baz 变成了 qux 中的 croak。"


3

->用于访问您拥有指针的数据。

例如,您可以像这样创建指向类型为int intVar的变量的指针ptr:

int* prt = &intVar;

您可以使用函数(例如foo)对其进行操作,只需取消引用该指针即可 - 调用函数时,将函数调用应用于指针所指向的变量,而不是内存位置的数值:
(*ptr).foo();

如果没有括号,编译器会因为运算符优先级将其理解为*(ptr.foo()),这不是我们想要的。

实际上,这与键入以下内容相同:

ptr->foo();

当我们使用->解引用指针时,会自动调用指针所指变量的函数foo()

同样地,我们也可以使用->来访问或设置类的成员:

myClass* ptr = &myClassMember;
ptr->myClassVar = 2; 

-1
你可以使用“->”来定义一个函数。
auto fun() -> int
{
return 100;
}

这不是一个lambda函数,而是一个真正的函数。箭头“->”表示函数的返回类型。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接