我正在学习如何超载“ - >”并且文件说: “operator->在它返回的值上再次被调用,直到达到operator->返回一个普通指针。之后,内置语义应用于该指针。”
虽然很清楚文档说的是什么,但基本上是超载的“ - >”一个类可以使用自己的“特殊指针”本身就是一个重载的“ - >”可以给出一个“特殊指针”等,直到找到“普通指针”,我找不到它的实际使用示例(除非它用于查找链接列表的最后一个元素)。
有人可以解释幕后的内容是什么(因为这种可能性没有提供“普通指针” - 所以我没有看到任何理由为它提供“特殊指针”)。
真实世界使用的一个例子也可能有所帮助,因为我可能错过了应用该行为的模型。
另一方面可能需要避免这种行为,怎么可能呢?
答案 0 :(得分:7)
嗯,->
运算符在特殊情况下工作。
可以称之为伪二元运算符。根据它的自然语法pointer->member
,它需要两个操作数:左侧的正常运行时操作数和右侧的相当“奇怪的”成员名称操作数。第二个操作数的“奇怪性”源于C ++语言没有用户可访问的概念来表示这些操作数。语言中没有任何内容可以将成员名称表示为操作数。没有办法通过代码将成员名称“传递”给用户定义的实现。成员名称是一个编译时实体,在这方面远程类似于常量表达式,但C ++中没有常量表达式可以指定成员。 (有成员指针的表达式,但成员本身没有)。
这在指定重载->
运算符的行为时会产生相当明显的困难:我们如何将->
右侧指定的内容(即成员名称)与写入的代码连接起来用户?不可能直接这样做。摆脱这种情况的唯一方法是间接地执行此操作:强制用户将重载的->
运算符的用户定义功能引导到某些现有内置运算符的功能中。内置运算符可以通过其核心语言功能自然地处理成员名称。
在这种特殊情况下,我们只有两个候选人可以将重载->
的功能引导至:内置->
和内置.
。为该角色选择内置->
是合乎逻辑的。这产生了一个有趣的副作用:编写重载->
运算符(由编译器隐式解包)的“链式”(递归)序列甚至无限递归序列(形成不良)的可能性。
非正式地说,每次使用智能指针时,都可以实际使用重载->
运算符的这些“递归”属性。如果您有一个智能指针sptr
指向具有成员member
的类对象,则成员访问语法保持完全自然,例如sptr->member
。您不必专门为sptr->->member
或sptr->.member
执行此操作,因为重载->
的隐式“递归”属性。
请注意,仅当您使用 operator 语法调用重载的->
运算符(即object->member
语法)时,才会应用此递归行为。但是,您也可以使用常规成员函数调用语法来调用重载的->
,例如object.operator ->()
。在这种情况下,调用作为普通函数调用执行,并且不发生->
的递归应用。这是避免递归行为的唯一方法。如果您实现了重载的->
运算符,其返回类型不支持->
运算符的其他应用程序(例如,您可以定义一个返回->
的重载int
,那么object.operator ->()
将是调用重载实现的唯一方法。任何使用object->member
语法的尝试都将是不正确的。
答案 1 :(得分:2)
我找不到真实使用它的例子(除非它用于查找链接列表的最后一个元素)。
我认为你误解了它的作用。它不用于取消引用列表元素并继续解除引用下一个元素。每次你打电话给operator->
你会得到一个不同的类型,关键是如果第二种类型也有一个operator->
它会被调用,这可能会返回一个不同的再次输入。想象一下,如果有帮助,x->->->i
而不是x->next->next->next
真实世界使用的一个例子也可能有所帮助,因为我可能错过了应用该行为的模型。
它对Execute Around Pointer模式很有用。
另一方面可能需要避免这种行为,怎么可能呢?
明确地呼叫运营商:
auto x = p.operator->();