天天看点

c++箭头操作符(->)重载函数

  箭头(->)操作符是个二元操作符,其左操作数是类对象的地址或者是重载了箭头运算符的类对象,右操作数是类的成员。箭头操作符重载函数只能是类的成员函数(参考为什么有的操作符重载函数只能是成员函数?)。

  箭头运算符的使用方法为:

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 ;
}
           

  (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 ;
}
           

  (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 ;
}