重载成员访问运算符 ->, .*

Overloading member access operators ->, .*

提问人:Bingo 提问时间:1/8/2012 最后编辑:Ulrich EckhardtBingo 更新时间:1/12/2020 访问量:112219

问:

我理解大多数运算符重载,除了成员访问运算符等。->.*->*

具体而言,传递给这些运算符函数的内容,以及应该返回的内容?

运算符如何工作(例如 ) 知道被推荐给哪个成员吗?它能知道吗?它甚至需要知道吗?operator->(...)

最后,是否有任何需要考虑的因素?例如,当重载类似 的东西时,通常您需要一个 const 版本和非 const 版本。成员访问算子是否需要常量和非常量版本?operator[]

C 运算符重载 C++-FAQ

评论

1赞 Alok Save 1/8/2012
我相信上面的 C++-Faq 触及了上面 Q 中提出的所有问题。
0赞 Fred Foo 1/8/2012
const和 非版本 不是必需的,但提供两者可能很有用。constoperator->
1赞 György Andrasek 1/8/2012
Смотритетакже: yosefk.com/c++fqa/operator.html
9赞 sbi 1/19/2012
@Als:FAQ 没有解释如何重载和 .事实上,它甚至没有提到他们!我觉得它们很少出现在常见问题解答中,但我很乐意将这个问题与常见问题解答联系起来。请不要将其作为常见问题解答的欺骗而关闭!->*.*
1赞 P i 12/29/2014
@sbi,我只是完全没有从你的(很棒的)常见问题解答中找到这个问题的链接,最终问了一个重复的问题。你能说得更明显吗?(如果已经很明显,请道歉)。

答:

10赞 John Chadwick 1/8/2012 #1

运算符不知道指向哪个成员,它只是提供一个对象来执行实际的成员访问。->

此外,我认为您没有理由不能提供常量和非常量版本。

7赞 Asaf 1/8/2012 #2

当您重载 operator->() 时(此处不传递任何参数),编译器实际执行的是递归调用 ->,直到它返回指向类型的实际指针。然后,它使用正确的成员/方法。

例如,这对于创建封装实际指针的智能指针类很有用。重载的运算符 > 被调用,执行它所做的任何操作(例如,锁定线程安全),返回内部指针,然后编译器为此内部指针调用 ->。

至于恒常性 - 在评论和其他答案中已经回答了(您可以而且应该同时提供两者)。

58赞 Totonga 1/8/2012 #3

运算符 -> 很特殊。

“它具有额外的非典型约束:它必须返回一个对象(或对对象的引用),该对象也具有指针取消引用运算符,或者它必须返回一个指针,该指针可用于选择指针取消引用运算符箭头所指向的内容。布鲁斯·埃克尔(Bruce Eckel):思考CPP第一卷:操作员>

为方便起见,提供了额外的功能,因此您不必调用

a->->func();

您可以简单地执行以下操作:

a->func();

这使得运算符 -> 与其他运算符重载不同。

评论

4赞 P i 12/29/2014
这个答案值得更多信任,您可以从该链接下载 Eckel 的书,信息在第一卷的第 12 章中。
0赞 Lei Zhao 8/31/2022
或者查看 C++11 标准的第 13.5.6 节。您可以在 N3242 上阅读免费草稿版本。
29赞 6502 1/8/2012 #4

您不能使成员访问过载(即第二部分)。但是,您可以重载一元取消引用运算符(即 what do 的第一部分)。.->*->

C++ 运算符基本上是两个步骤的并集,如果您认为这等价于 .C++ 允许您自定义在作为类的实例时如何处理该部件。->x->y(*x).y(*x)x

重载的语义有些奇怪,因为 C++ 允许您返回一个常规指针(它将用于查找指向的对象)或返回另一个类的实例(如果该类还提供运算符)。在第二种情况下,从这个新实例继续搜索取消引用的对象。->->

评论

3赞 Bingo 1/9/2012
很好的解释!我想这同样是 的意思,因为它等价于 ?->*(*x).*
191赞 Potatoswatter 1/9/2012 #5

->

这是唯一真正棘手的问题。它必须是一个非静态成员函数,并且不带任何参数。返回值用于执行成员查找。

如果返回值是类类型的另一个对象,而不是指针,则后续成员查找也由函数处理。这称为“向下钻取行为”。该语言将调用链接在一起,直到最后一个调用返回指针。operator->operator->

struct client
    { int a; };

struct proxy {
    client *target;
    client *operator->() const
        { return target; }
};

struct proxy2 {
    proxy *target;
    proxy &operator->() const
        { return * target; }
};

void f() {
    client x = { 3 };
    proxy y = { & x };
    proxy2 z = { & y };

    std::cout << x.a << y->a << z->a; // print "333"
}

->*

这个很棘手,因为它没有什么特别之处。非重载版本要求左侧有一个指向类类型的指针对象,右侧有一个指向成员类型的指针对象。但是当你重载它时,你可以接受任何你喜欢的参数,并返回任何你想要的东西。它甚至不必是非静态成员。

换句话说,这个只是一个普通的二进制运算符,如 、 和 。Смотритетакже: 免费的操作员>*重载是邪恶的吗?+-/

.*.

这些不能重载。当左侧为类类型时,已经有一个内在的含义。也许能够为左侧的指针定义它们会有点意义,但语言设计委员会认为这将是更令人困惑而不是有用的。

重载 、 、 和 只能在表达式未定义的情况下填充,它永远不能更改在没有重载的情况下有效的表达式的含义。->->*..*

评论

2赞 Matt 2/17/2013
你的最后一句话并不完全正确。例如,您可以重载运算符,即使它未重载也有效。new
6赞 Potatoswatter 2/18/2013
@Matt,总是重载,或者重载规则并不真正适用于它(13.5/5:分配和释放函数,运算符 new、运算符 new[]、运算符 delete 和运算符 delete[],在 3.7.4 中进行了完整描述。除非在 3.7.4 中明确说明,否则本子句其余部分中的属性和限制不适用于它们。但是,重载一元或二进制 、 或 ,或者添加 的重载 ,或者重载无作用域枚举类型的几乎任何内容,都可以更改表达式的含义。澄清了声明,谢谢!new&&&||,operator=
0赞 Armen Michaeli 3/25/2023
我不明白“指向类类型的指针对象”到底是什么意思?