Оператор перегрузки -

17

Вот мой пример кода:

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 '.'
}

Почему компилятор пытается «переместить ответственность» для operator- & gt; от Y до X? Когда я реализую X :: op- & gt; то я не могу вернуть X там - ошибка компиляции говорит «бесконечная рекурсия» при возвращении некоторого Z из X :: op- & gt; снова говорит, что Z не имеет operator- & gt ;, таким образом, все выше и выше в иерархии.

Может ли кто-нибудь объяснить это интересное поведение? :)     

задан user602855 04.02.2011 в 10:07
источник

4 ответа

18

Проблема заключается в том, что operator -> должен возвращать указатель , а не ссылку . Идея состоит в том, что operator -> должен возвращать указатель на реальный объект, который должен иметь указатель, примененный к нему. Например, для класса с перегруженным operator -> код

myClass->myValue;

означает

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

Проблема с вашим кодом заключается в том, что operator -> возвращает ссылку, поэтому запись

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

является совершенно законным, потому что вы явно вызываете оператор, но пишите

myClass->f();

является незаконным, поскольку компилятор пытается его расширить до

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

, а тип возврата operator-> не является указателем.

Чтобы исправить это, измените свой код, чтобы вернуть указатель в operator -> . Если вы хотите перегрузить оператора, чтобы вернуть ссылку, перегрузите operator * ; Различия в указателях действительно должны давать ссылки.

    
ответ дан templatetypedef 04.02.2011 в 10:11
источник
  • Я бы не сказал, что он должен возвращать указатель, так как все, что он возвращает, должно поддерживать operator->. –  GManNickG 04.02.2011 в 10:20
  • @ GMan- Хорошая точка. Я собирался для простоты здесь, но ты прав. Есть некоторые действительно забавные трюки, которые вы можете сделать с помощью умных указателей, которые полагаются на эту технику. –  templatetypedef 04.02.2011 в 10:27
  • @GMan: Так как такие типы называются умными указателями, я не думаю, что templatetypedef ошибочно использует термин указатель, он просто использует его в общем смысле. –  Ben Voigt 04.02.2011 в 21:00
  • Хотя и не совсем корректно «Проблема в том, что оператор -> должен возвращать указатель, а не ссылку». ответил на мой вопрос в одном предложении. –  mat_geek 02.05.2014 в 04:58
19

Так как перегрузка -> работает на C ++.

При использовании перегруженного -> выражение a->b переводится в a.operator->()->b . Это означает, что ваш перегруженный оператор -> должен вернуть то, что будет поддерживать другое приложение оператора -> . По этой причине один вызов перегруженного -> может превратиться в длинную цепочку вызовов перегруженного -> s, пока он не достигнет приложения встроенного -> , которое завершает цепочку.

В вашем случае вам нужно вернуть X* из вашего перегруженного -> , а не X& .

    
ответ дан AnT 04.02.2011 в 10:15
источник
2

Синтаксис неверен:

Т- & GT; Т2

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

Посмотрите на статью Википедии: Операторы на C и C ++

Если вы хотите перегрузить, вы должны использовать правильный синтаксис для перегруженного оператора

    
ответ дан Yochai Timmer 04.02.2011 в 10:13
источник
1

Вероятно, вы хотите:

class Y : public X
{
public:
        X* operator->() { return this; }
        void f() {}
};
    
ответ дан Tomek 04.02.2011 в 10:47
источник