我理解大多数运算符重载,但成员访问运算符->
,.*
,->*
等除外。
特别是传递给这些运算符函数的内容以及应返回的内容是什么?
运营商如何运作(例如operator->(...)
)知道被提及的成员?可以知道吗?它甚至需要知道吗?
最后,是否需要考虑常见因素?例如,当重载像operator[]
这样的东西时,通常你需要const和非const版本。成员访问运算符是否需要const和非const版本?
答案 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;对于这个内部指针。
至于常数 - 它已在评论和其他答案中得到回答(你可以而且应该同时提供)。