提问人:Bingo 提问时间:1/8/2012 最后编辑:Ulrich EckhardtBingo 更新时间:1/12/2020 访问量:112219
重载成员访问运算符 ->, .*
Overloading member access operators ->, .*
问:
我理解大多数运算符重载,除了成员访问运算符等。->
.*
->*
具体而言,传递给这些运算符函数的内容,以及应该返回的内容?
运算符如何工作(例如 ) 知道被推荐给哪个成员吗?它能知道吗?它甚至需要知道吗?operator->(...)
最后,是否有任何需要考虑的因素?例如,当重载类似 的东西时,通常您需要一个 const 版本和非 const 版本。成员访问算子是否需要常量和非常量版本?operator[]
答:
运算符不知道指向哪个成员,它只是提供一个对象来执行实际的成员访问。->
此外,我认为您没有理由不能提供常量和非常量版本。
当您重载 operator->() 时(此处不传递任何参数),编译器实际执行的是递归调用 ->,直到它返回指向类型的实际指针。然后,它使用正确的成员/方法。
例如,这对于创建封装实际指针的智能指针类很有用。重载的运算符 > 被调用,执行它所做的任何操作(例如,锁定线程安全),返回内部指针,然后编译器为此内部指针调用 ->。
至于恒常性 - 在评论和其他答案中已经回答了(您可以而且应该同时提供两者)。
运算符 -> 很特殊。
“它具有额外的非典型约束:它必须返回一个对象(或对对象的引用),该对象也具有指针取消引用运算符,或者它必须返回一个指针,该指针可用于选择指针取消引用运算符箭头所指向的内容。布鲁斯·埃克尔(Bruce Eckel):思考CPP第一卷:操作员>
为方便起见,提供了额外的功能,因此您不必调用
a->->func();
您可以简单地执行以下操作:
a->func();
这使得运算符 -> 与其他运算符重载不同。
评论
您不能使成员访问过载(即第二部分)。但是,您可以重载一元取消引用运算符(即 what do 的第一部分)。.
->
*
->
C++ 运算符基本上是两个步骤的并集,如果您认为这等价于 .C++ 允许您自定义在作为类的实例时如何处理该部件。->
x->y
(*x).y
(*x)
x
重载的语义有些奇怪,因为 C++ 允许您返回一个常规指针(它将用于查找指向的对象)或返回另一个类的实例(如果该类还提供运算符)。在第二种情况下,从这个新实例继续搜索取消引用的对象。->
->
评论
->*
(*x).*
->
这是唯一真正棘手的问题。它必须是一个非静态成员函数,并且不带任何参数。返回值用于执行成员查找。
如果返回值是类类型的另一个对象,而不是指针,则后续成员查找也由函数处理。这称为“向下钻取行为”。该语言将调用链接在一起,直到最后一个调用返回指针。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"
}
->*
这个很棘手,因为它没有什么特别之处。非重载版本要求左侧有一个指向类类型的指针对象,右侧有一个指向成员类型的指针对象。但是当你重载它时,你可以接受任何你喜欢的参数,并返回任何你想要的东西。它甚至不必是非静态成员。
换句话说,这个只是一个普通的二进制运算符,如 、 和 。Смотритетакже: 免费的操作员>*重载是邪恶的吗?+
-
/
.*
和.
这些不能重载。当左侧为类类型时,已经有一个内在的含义。也许能够为左侧的指针定义它们会有点意义,但语言设计委员会认为这将是更令人困惑而不是有用的。
重载 、 、 和 只能在表达式未定义的情况下填充,它永远不能更改在没有重载的情况下有效的表达式的含义。->
->*
.
.*
评论
new
new
&
&&
||
,
operator=
评论
const
和 非版本 不是必需的,但提供两者可能很有用。const
operator->
->*
.*