Нужно ли возвращать ссылку на объект при перегрузке оператора предварительного приращения? - PullRequest
8 голосов
/ 16 июня 2011

Могу ли я использовать:

MyClass& MyClass::operator++ () {
    a++;  // private var of MyClass
    return (*this);
}

Или это может быть:

MyClass MyClass::operator++ ();

В чем разница?


Спасибо за ответы.У меня есть другая проблема.

Многие люди делают что-то подобное:

MyClass& MyClass::operator++();
MyClass MyClass::operator++(int);

Разве это не нелогично?Пожалуйста, приведите несколько примеров, если можете.

Я знаю, что первая версия является преинкрементной, а вторая - постинкрементной, но я спрашиваю, почему первая возвращает ссылку, а вторая нет?Он находится в том же коде (классе) и в том же коде.

Ответы [ 5 ]

16 голосов
/ 16 июня 2011

Нет, у вас нет для возврата ссылки на ваш объект, когда вы перегружаете оператор предварительного увеличения.На самом деле вы можете вернуть все, что захотите, MyClass, int, void, что угодно.

Это проблема дизайна - вы должны спросить себя, что является самым полезным дляпользователей вашего класса, которые вы можете вернуть.

Как правило, операторы классов наиболее полезны, когда они вызывают наименьшую путаницу, т. е. когда они работают наиболее похожими на базовые типы операторов.В этом случае оператор предварительного увеличения базового типа:

int  i = 7;
j = ++i;

увеличивает переменную и возвращает новое значение.Если это единственное использование, которое вы хотите иметь MyClass, то достаточно вернуть копию вашего класса.

Но оператор предварительного увеличения базового типа фактически возвращает значение lvalue.Итак, это законно:

int i = 7;
int *p = &++i;

Если вы хотите поддержать такую ​​операцию, вы должны вернуть ссылку.

Есть ли конкретная причина, по которой вы не хотите возвращатьсяссылка?Разве это не правильно сформулированная концепция для вашего конкретного класса?Если это так, рассмотрите возможность возврата void.В этом случае это выражение: ++myObject допустимо, а myOtherObject = ++myObject - нет.

2 голосов
/ 18 февраля 2012

Это не обязательно, но мы должны попытаться сделать перегрузку оператора интуитивно понятной, и она должна работать в соответствии с оператором, который перегружается.

Если мы сделаем int i = 10; я ++ = 0 Тогда второе утверждение недопустимо, оно говорит, что требует lvalue, так как i ++ обозначает старое состояние i, а не хранилища ... пока ++ i = 0 отлично работает .. так что просто для того, чтобы синхронизировать его с фактической версией префикса операторов, нужно было возвращать refence, чтобы его возвращаемое значение могло рассматриваться как lvalue в выражениях.

2 голосов
/ 16 июня 2011

Для второго вопроса:

Префикс возвращает ссылку, как и ожидалось.Postfix возвращает копию в соответствии с поведением оператора (ов) postfix.

Разбейте его просто на int:

int c = 0;

if(++c)
{
   // true, prefix increments prior to the test
}

c = 0;

if(c++)
{
   // false, c now == 1, but was incremented after the test
}

Для реализации этого поведения в классе требуется, чтобы копия былавозвращается, потому что оператор постфикса изменил состояние объекта.

Если программе не требуется истинная операция постфикса, вы, конечно, можете реализовать то, что вы хотите.Хотя существуют стандартные способы написания этих операторов (которые понятны большинству программистов на C ++), на самом деле ничто не мешает вам реализовать это различными способами.

Аргумент, предоставленный о неправильной функциональности, окружающей (obj++)++, на самом деле не являетсяважно, так как этот код даже не будет компилироваться для типов POD (по крайней мере, в Visual Studio 2010), поскольку для типов POD возвращается копия, и эта временная копия не может использоваться отдельно как l-значение.

Тем не менее, для префиксного оператора предпочтительной является ссылка, так как она обеспечивает правильное поведение для цепочки операции (++(++obj)).

2 голосов
/ 16 июня 2011

Вы можете вернуть все, что хотите.void, ссылка на себя, копия себя, что-то еще.В зависимости от того, что вы предпочитаете (или вам нужно).

Если вы планируете использовать оператор ++ в цепочечных выражениях (например, (++obj).something()), верните ссылку.Если вы этого не сделаете, то void - это нормально.

Помните, что в конце операторы похожи на обычные методы: вы можете делать с ними все, что хотите, при условии, что вы уважаете их прототип.

1 голос
/ 16 июня 2011

Да, вы должны вернуться по ссылке. Нет необходимости в скобках вокруг *this.

РЕДАКТИРОВАТЬ : Отвечая на ваш комментарий ... У вас нет для возврата по ссылке. Но в целом мы следуем некоторым рекомендациям, которые заставляют наши классы вести себя «как положено» по сравнению со встроенной семантикой таких операторов. Возможно, вы захотите взглянуть на http://www.parashift.com/c++-faq-lite/operator-overloading.html.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...