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


129

据我所知大多数运算符重载,与成员访问运营商外->.*->*等。

特别是,什么传递给这些运算符,应该返回什么?

操作员功能(例如operator->(...))如何知道所引用的成员?能知道吗 它甚至需要知道吗?

最后,是否需要考虑任何常量注意事项?例如,当重载类似的东西时operator[],通常将需要const版本和非const版本。成员访问运算符是否需要const和非const版本?


1
我相信上面的C ++ -在所有常见问题触摸到Q的要求在上述Q.
阿洛克保存

const和非const版本operator->不是必需的,但同时提供可能是有用的。
Fred Foo 2012年


9
@Als:常见问题解答未解释如何重载->*.*。实际上,它甚至都没有提到它们!我觉得他们很少出现在FAQ中,但是我很乐意将这个问题与FAQ链接起来。请不要关闭它作为常见问题解答的重复!
2012年

@sbi,我完全无法从您的(真棒)常见问题解答中找到此问题的链接,并最终提出了一个重复的问题。你能使它更明显吗?(很抱歉,如果已经很明显)。
P I

Answers:


144

->

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

如果返回值是类类型的另一个对象,而不是指针,则随后的成员查找也由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
您的最后声明并不完全正确。例如,您可以重载new运算符,即使该运算符即使未重载也有效。
Matt

6
@Matt好,new总是重载,或者重载规则并不真正适用于它(13.5 / 5:分配和释放函数,运算符new,运算符new [],运算符delete和运算符delete []在3.7中进行了完整描述0.4。本节的剩余部分中的属性和限制并不适用于他们,除非在3.7.4明确说明。)但是,重载一元&或二元&&||,,或添加的过载operator=,或者只是重载任何东西对于未范围枚举类型,可以更改表达式的含义。澄清声明,谢谢!
Potatoswatter

41

运算符->很特殊。

“它具有附加的非典型约束:它必须返回还具有指针取消引用操作符的对象(或对对象的引用),或者必须返回可以用于选择指针取消引用操作符箭头所指向的指针。 ” 布鲁斯·埃克尔(Bruce Eckel):思考CPP第一卷:操作员->

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

a->->func();

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

a->func();

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


3
这个答案值得更多功劳,您可以从该链接下载Eckel的书,其信息在第一卷的第12章中。
P I

26

您不能过载成员访问权限.(即,第二部分->)。但是,您可以重载一元解引用运算符*(即,该->函数的第一部分)。

C ++ ->运算符基本上是两个步骤的结合,如果您认为x->y等效于,则很清楚(*x).y(*x)x属于类的实例时,C ++允许您自定义如何处理零件。

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


2
很好的解释!我想这对于意味着相同->*,因为它等效于(*x).*?的形式。
宾果游戏2012年

10

->运营商不知道正在指向什么成员,它只是提供了一个对象来执行实际的成员访问。

另外,我认为没有理由不能提供const和非const版本。


7

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

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

至于constness-在评论和其他答案中都得到了回答(您可以并且应该同时提供)。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.