简体   繁体   中英

Why overloaded de-reference operator doesn't work the same way as the arrow operator?

Again reading C++ primer 5 ed. by lipmann now I've read about Member access operators overloading. Everything is clear to me except:

struct A
{
    int& operator* () {return *p;}
    void foo()const{cout << "A::foo()\n";}
    int* p = new int(5);
};

struct B
{
    A& operator*(){return a;}
    A* operator->(){return &a;}
    A a{};
};

struct C
{
    B& operator*(){return b;}
    B& operator->(){return b;}
    B b{};
};


int main()
{

    C c;
    //cout << *c << endl; // error.
    c->foo(); // works

}
  • What I've learned is that the arrow operator can be overloaded and must be a member function. And if I see an expression like in main c->foo() I can think that c is either a built-in pointer to an object of a class type that has a member function called foo thus fetch it. Or (like the case in main) c is an object of a class type that has defined its own -> . So because c here is an object that expression calls c 's arrow operator which returns an object of class B type which itself calls its arrow operator until it returns B object which its -> returns a built in pointer to A object and in this case it is de-referenced and the resulted object is used to fetch foo() function. So it recursively calls itself until a built-in pointer is returned and that pointer must point to an object that has that fetched-member.

  • What I don't understand: Why the de-reference operator doesn't work the same way? So why de-referencing c doesn't call the * operator of b and so on as long as it returns an object that has defined it de-reference operator?

  • Please don't argue about memory leak in A the purpose is for brevity.

That's just how -> (member access), and * (indirection) are defined .

As you have pointed out, -> will recursively call -> on whatever it returns, until it resolves in a pointer. At this point, you can do things that you would like to do with a pointer.

The * operator is simply not defined to work that way. There is no recursive call to * on whatever is returned.

In your case, you could get to foo using indirection, but you will have to do so manually, like this:

(**c).foo();

Note also, that your particular example doesn't compile because *c returns a reference to an object of type B , which doesn't have an operator<< defined for it.

The reason is that the dereference operator is inherently unary (returning a reference), so it can be overloaded just like any other operator. And it can be used recursively, if desired, you just need to apply it again.

OTOH, -> is used more like a binary operator... but the thing on the right of it is not a value but rather a name . That name has to be looked up somewhere. So the compiler definitely needs an object. Thus the operator is defined as unary. But it is not used as unary, so you can just apply it again, if desired. So it is defined the other way around: you can rely on recursive application, or “opt-out” of it by returning raw pointer.

Disclaimer: that is just how I see this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM