->
This is the only really tricky one. It must be a nonstatic member function, and it takes no arguments. The return value is used to perform the member lookup.
If the return value is another object of class type, not a pointer, then the subsequent member lookup is also handled by an operator->
function. This is called the "drill-down behavior." The language chains together the operator->
calls until the last one returns a pointer.
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"
}
->*
This one is only tricky in that there is nothing special about it. The non-overloaded version requires an object of pointer to class type on the left-hand side and an object of pointer to member type on the right. But when you overload it, you can take any arguments you like and return anything you want. It doesn't even have to be a nonstatic member.
In other words, this one is just a normal binary operator like +
, -
, and /
. See also: Are free operator->* overloads evil?
.*
and .
These cannot be overloaded. There is already a built-in meaning when the left-hand side is of class type. Perhaps it would make a little sense to be able to define them for a pointer on the left-hand side, but the language design committee decided that would be more confusing than useful.
Overloading ->
, ->*
, .
, and .*
can only fill in cases where an expression would be undefined, it can never change the meaning of an expression that would be valid with no overloading.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…