重载成员访问操作符 – >,。*(C ++)
我理解大多数运算符重载,除了成员访问运算符->
, .*
, ->*
等
特别是传递给这些运算符函数的是什么,应该返回什么?
操作符是如何工作的(如operator->(...)
)是否知道被引用的成员? 可以知道吗? 它甚至需要知道吗?
最后,是否有需要考虑的常量因素? 例如,当重载类似operator[]
东西时,通常你需要一个const和非const的版本。 成员访问操作符是否需要const和非const版本?
->
这是唯一一个非常棘手的问题。 它必须是一个非静态成员函数,并且不需要任何参数。 返回值用于执行成员查找。
如果返回值是类types的另一个对象,而不是指针,则后续成员查找也由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 << xa << y->a << z->a; // print "333" }
->*
这一个只是棘手的,没有什么特别的。 非重载版本需要一个指向左侧类types指针的对象和右侧成员types指针对象。 但是,当你超载时,你可以采取任何你喜欢的参数,并返回任何你想要的。 它甚至不必是一个非静态成员。
换句话说,这个只是一个普通的二元运算符,像+
, -
和/
。 另见: 免费的运营商 – > *重载邪恶?
.*
和.
这些不能被重载。 当左边是types时,已经有了一个内置的意思。 也许能够将它们定义为左侧的指针是有道理的,但是语言devise委员会认为这会比有用的更困惑。
重载->
, ->*
,。 , .*
只能填充expression式未定义的情况下,它永远不能改变一个expression式的含义,不会超载。
您不能超载成员访问.
(即什么->
的第二部分)。 但是,你可以重载一元解引用操作符*
(即第一部分是什么->
)。
C ++ ->
运算符基本上是两个步骤的联合,如果您认为x->y
等同于(*x).y
,则这很清楚。 当x
是你的类的一个实例时,C ++允许你自定义如何处理(*x)
部分。
->
重载的语义有点奇怪,因为C ++允许你返回一个常规的指针(它将被用来查找指向的对象),或者如果这个类还提供了一个->
操作符,它将返回另一个类的实例。 在第二种情况下,从这个新实例继续search解除引用的对象。
运算符 – >是特殊的。
“它有另外的非典型约束:它必须返回一个对象(或者一个对象的引用),它也有一个指针解引用操作符,或者它必须返回一个指针,可以用来select指针解除引用操作符箭头指向的内容。 “ 布鲁斯·艾克尔(Bruce Eckel):思考CPP Vol-one:运营商 – >
提供额外的function是为了方便,所以你不必打电话
a->->func();
你可以简单地做:
a->func();
这使得运算符 – >与其他运算符重载不同。
->
运算符不知道正在指向什么成员,它只是提供一个对象来执行实际的成员访问。
另外,我看不出为什么你不能提供const和非const版本。
当你重载operator – >()(这里没有parameter passing)时,编译器实际上做的是recursion调用 – >直到它返回一个实际的指针types。 然后使用正确的成员/方法。
例如,创build封装实际指针的智能指针类很有用。 重载的operator->被调用,执行任何操作(例如locking线程安全),返回内部指针,然后编译器调用 – >来获取这个内部指针。
至于常量 – 已经在评论和其他答案(你可以,应该提供两者)中得到回答。