重载成员访问运算符 - >,。*(C ++)

时间:2012-01-08 13:17:57

标签: c++ operator-overloading c++-faq

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

特别是传递给这些运算符函数的内容以及应返回的内容是什么?

运营商如何运作(例如operator->(...))知道被提及的成员?可以知道吗?它甚至需要知道吗?

最后,是否需要考虑常见因素?例如,当重载像operator[]这样的东西时,通常你需要const和非const版本。成员访问运算符是否需要const和非const版本?

5 个答案:

答案 0 :(得分:127)

->

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

如果返回值是类类型的另一个对象,而不是指针,则后续成员查找也由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"
}

->*

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

换句话说,这个只是一个普通的二元运算符,如+-/。另见:Are free operator->* overloads evil?

.*.

这些不能超载。当左侧是类型时,已经存在内置意义。也许能够为左侧的指针定义它们会有一点意义,但语言设计委员会认为这将更加混乱而不是有用。

重载->->*..*只能填写表达式未定义的情况,它永远不会改变表达式的含义在没有超载的情况下有效。

答案 1 :(得分:26)

运营商 - &gt;很特别。

“它有额外的非典型约束:它必须返回一个对象(或对一个对象的引用),它也有一个指针解除引用操作符,或者它必须返回一个指针,该指针可用于选择指针取消引用操作符箭头是什么指着。“ Bruce Eckel: Thinking CPP Vol-one : operator->

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

a->->func();

您可以这样做:

a->func();

这使得运营商 - &gt;与其他运算符重载不同。

答案 2 :(得分:21)

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

C ++ ->运算符基本上是两个步骤的结合,如果您认为x->y等同于(*x).y,则很明显。当(*x)是您班级的一个实例时,C ++允许您自定义如何处理x部分。

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

答案 3 :(得分:9)

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

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

答案 4 :(得分:6)

当你重载operator-&gt;()(这里没有传递参数)时,编译器实际上做的是调用 - &gt;递归直到它返回一个指向类型的实际指针。然后它使用正确的成员/方法。

例如,这可用于创建封装实际指针的智能指针类。重载运算符 - &gt;无论它做什么(例如锁定线程安全),返回内部指针然后编译器调用 - &gt;对于这个内部指针。

至于常数 - 它已在评论和其他答案中得到回答(你可以而且应该同时提供)。

相关问题