19

Here is my code example:

class X
{
public:
        void f() {}
};

class Y : public X
{
public:
        X& operator->() { return *this; }
        void f() {}
};

int main()
{
        Y t;
        t.operator->().f(); // OK
        t->f(); // error C2819: type 'X' does not have an overloaded member 'operator ->'
                // error C2232: '->Y::f' : left operand has 'class' type, use '.'
}

Why the compiler is trying to "move the responsibility" for operator-> from Y to X? When I implement X::op-> then I cannot return X there - compile error says "infinite recursion" while returning some Z from X::op-> again says that Z doesn't have operator->, thus going higher and higher in hierarchy.

Can anyone explain this interesting behavior? :)

CashCow
  • 30,981
  • 5
  • 61
  • 92
user602855
  • 193
  • 1
  • 4

4 Answers4

21

The problem is that operator -> is supposed to return a pointer, not a reference. The idea is that operator -> should return a pointer to the real object that should have the pointer applied to it. For example, for a class with an overloaded operator ->, the code

myClass->myValue;

translates into

(myClass.operator-> ())->myValue;

The problem with your code is that operator -> returns a reference, so writing

myClass.operator->().f();

is perfectly legal because you're explicitly invoking the operator, but writing

myClass->f();

is illegal, because the compiler is trying to expand it to

myClass.operator->()->f();

and the return type of operator-> isn't a pointer.

To fix this, change your code so that you return a pointer in operator ->. If you want to overload an operator to return a reference, overload operator *; pointer dereferences should indeed produce references.

templatetypedef
  • 362,284
  • 104
  • 897
  • 1,065
  • 11
    I wouldn't say it's suppose to return a pointer, just that whatever it returns needs to support `operator->`. – GManNickG Feb 04 '11 at 09:20
  • 1
    @GMan- Good point. I was going for simplicity here, but you're correct. There are some really fun tricks you can pull off with smart pointers that rely on this technique. – templatetypedef Feb 04 '11 at 09:27
  • @GMan: Since such types are collectively called *smart pointers*, I don't think templatetypedef is wrong to use the term *pointer*, he's just using it in a general sense. – Ben Voigt Feb 04 '11 at 20:00
  • 1
    Although not completely correct "The problem is that operator -> is supposed to return a pointer, not a reference." answered my question in one sentence. – mat_geek May 02 '14 at 02:58
20

Because that's how overloaded -> works in C++.

When you use overloaded ->, expression a->b is translated into a.operator->()->b. This means that your overloaded operator -> must return something that will itself support another application of operator ->. For this reason a single invocation of overloaded -> might turn into a long chain of invocations of overloaded ->s until it eventually reaches an application of built-in ->, which ends the chain.

In your case you need to return X* from your overloaded ->, not X&.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
2

The syntax is wrong, should be:

T->T2

T2* T::operator ->();​

Look at wikipedia's article: Operators in C and C++

If you want to overload, you must use the right syntax for the overloaded operator

Yochai Timmer
  • 48,127
  • 24
  • 147
  • 185
1

You probably want:

class Y : public X
{
public:
        X* operator->() { return this; }
        void f() {}
};
Tomek
  • 4,554
  • 1
  • 19
  • 19