箭头(->)操作符是个二元操作符,其左操作数是类对象的地址或者是重载了箭头运算符的类对象,右操作数是类的成员。箭头操作符重载函数只能是类的成员函数(参考为什么有的操作符重载函数只能是成员函数?)。
箭头运算符的使用方法为:
obj->mem;
obj->func();
obj为某个类对象的地址,mem和func()分别是该对象的成员变量和成员函数,这样的用法是我们之前学习的。在引入操作符重载后,obj还可以是重载了->操作符的类对象(注意是对象而非地址),mem和func()依旧是类对象的成员,但是注意,它不再是obj对象的成员。
对于上述代码语句,编译器是这样处理的:
步骤(1):倘若obj是指针(或者说地址),指向的是具有成员变量mem(成员函数func())的类对象,那么obj->mem返回成员变量mem,obj->func()调用成员函数func();
步骤(2):倘若obj是一个重载了->操作符的类对象,那么调用obj对象的operator->()函数,该函数的返回值有两种情况:①返回指针,执行步骤(1);②返回重载了->操作符的类对象,执行步骤(2),直至返回的是指针。
所以若obj是一个重载了->的类对象,那么mem和func()将不是obj的成员,而是->运算符重载函数最终返回的指针指向的对象的成员。
用下面代码加深理解:
(1)左操作数是对象的指针
using namespace std;
struct A
{
void func() { printf("A::func()\n"); }
};
int main(void)
{
A *aobj = new A;
aobj->func(); //简单,打印A::func()
return 0;
}
(2)左操作数是重载->操作符的类对象,该重载函数返回的是某个对象的指针
struct C
{
void func() { printf("C::func()\n"); }
};
struct B
{
C m_c;
C* operator->() { return &m_c; }
};
int main(void)
{
B bobj; //bobj是一个对象,但它重载了->操作符
bobj->func(); //执行的是C::func(),即打印C::func()
return 0;
}
(3)左操作数是重载->操作符的类对象,重载函数返回的是另一个重载了->操作符的类的对象
struct F
{
void func() { printf("F::func()\n"); }
};
struct E
{
F m_f;
F* operator->() { return &m_f; } //返回m_f对象的地址
};
struct D
{
E m_e;
E operator->() { return m_e; } //返回m_e对象,该对象重载了->操作符
};
int main(void)
{
D d;
d->func(); //等价于d.operator->().operator->()->func(),打印F::func()
return 0;
}