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

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

18 голосов
/ 04 февраля 2011

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

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-> с Y на X?Когда я реализую X :: op->, тогда я не могу вернуть туда X - ошибка компиляции говорит «бесконечная рекурсия», а возвращение некоторого Z из X :: op-> снова говорит о том, что Z не имеет оператора->, таким образом, поднимаясь выше ивыше по иерархии.

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

Ответы [ 4 ]

19 голосов
/ 04 февраля 2011

Потому что так перегружается -> в C ++.

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

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

19 голосов
/ 04 февраля 2011

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

myClass->myValue;

переводится в

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

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

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

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

myClass->f();

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

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

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

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

2 голосов
/ 04 февраля 2011

Синтаксис неправильный, должно быть:

T-> T2

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

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

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

1 голос
/ 04 февраля 2011

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

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