Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

recursive application of operator->

Tags:

c++

It is said that the arrow operator is applied recursively. But when I try to execute the following code, it prints gibberish when it is supposed to print 4.

class dummy
{
public:
    int *p;

    int operator->()
    {
        return 4;
    }
};

class screen 
{
public:
    dummy *p;

    screen(dummy *pp): p(pp){}
    dummy* operator->()
    {
        return p;
    }
};

int main()
{
    dummy *d = new dummy;
    screen s(d);
    cout<<s->p;
    delete d;
}
like image 381
user1232138 Avatar asked May 05 '12 09:05

user1232138


3 Answers

What Stanley meant by “recursive” is just that the operator is applied to every returned object until the returned type is a pointer.

Which happens here on the first try: screen::operator -> returns a pointer. Thus this is the last call to an operator -> that the compiler attempts. It then resolves the right-hand sice of the operator (p) by looking up a member in the returned pointee type (dummy) with that name.

Essentially, whenever the compiler finds the syntax aᵢ->b in code, it essentially applies the following algorithm:

  1. Is aᵢ of pointer type? If so, resolve member b of *aᵢ and call (*aᵢ).b.
  2. Else, try to resolve aᵢ::operator ->
    1. On success, set aᵢ₊₁ = aᵢ::operator ->(). Goto 1.
    2. On failure, emit a compile error.

I’m hard-pressed to come up with a short, meaningful example where a chain of operator -> invocations even makes sense. Probably the only real use is when you write a smart pointer class.

However, the following toy example at least compiles and yields a number. But I wouldn’t advise actually writing such code. It breaks encapsulation and makes kittens cry.

#include <iostream>

struct size {
    int width;
    int height;
    size() : width(640), height(480) { }
};

struct metrics {
    size s;
    size const* operator ->() const {
        return &s;
    }
};

struct screen {
    metrics m;
    metrics operator ->() const {
        return m;
    }
};

int main() {
    screen s;
    std::cout << s->width << "\n";
}
like image 147
Konrad Rudolph Avatar answered Nov 11 '22 09:11

Konrad Rudolph


C++ Primer (5th edition) formulates it as follows on page 570:

The arrow operator never loses its fundamental meaning of member access. When we overload arrow, we change the object from which arrow fetches the specified member. We cannot change the fact that arrow fetches a member.

like image 44
AlwaysLearning Avatar answered Nov 11 '22 08:11

AlwaysLearning


The deal is once screen::operator->() returns a pointer (dummy*) the recursion stops because built-in (default) -> in used on that pointer. If you want recursion you should return dummy or dummy& from screen::operator->()

like image 1
sharptooth Avatar answered Nov 11 '22 07:11

sharptooth