Какой вариант C ++ Operator Overloading мне следует использовать?И почему? - PullRequest
3 голосов
/ 06 ноября 2011

Здесь приведены 3 варианта перегрузки оператора сложения (+).

Какой вариант мне использовать и почему?

class MyClass {
    int myInteger;
    double myDouble;
    public:
        MyClass(int i, double d) {
        myInteger = i;
        myDouble = d;
    }

    // Variation - 1
    //--------------
    MyClass operator +(MyClass rhsObj) {
        return MyClass(this->myInteger + rhsObj.myInteger, this->myDouble + rhsObj.myDouble);
    }

    // Variation - 2
    //--------------
    MyClass &operator +(MyClass &rhsObj) {
        rhsObj.myInteger = this->myInteger + rhsObj.myInteger;
        rhsObj.myDouble = this->myDouble + rhsObj.myDouble;

        return rhsObj;
    }

    // Variation - 3
    //--------------    
    MyClass &operator +(MyClass &rhsObj) {
        this->myInteger = this->myInteger + rhsObj.myInteger;
        this->myDouble = this->myDouble + rhsObj.myDouble;

        return *this;
    }
};


int main() {
    MyClass objOne(10, 10.5);
    MyClass objTwo(20, 20.5);

    MyClass objThree = objOne + objTwo;
}

Каким должен быть случай оператора присваивания (=)? Какой вариант следует использовать?

Ответы [ 5 ]

10 голосов
/ 06 ноября 2011

Зависит от того, что вам нужно.

Во-первых, о ваших версиях - очевидно,

  • «Вариация - 1» создает новый объект, не касаясь двух операндов.
  • «Variation - 2» сохраняет результат во втором операнде
  • «Variation - 3» сохраняет результат в первом операнде в «this».

Скорее всего, вариант - 1 является наиболее предпочтительным.

Почему?Из-за побочных эффектов.Если вы видите выражение вроде:

a = b + c;

независимо от типа a, b и c, что бы вы подумали?Я думаю, что a - это сумма b, а c И b и c - нетронутыми, я имею в виду - со старыми значениями.
Предположим, например:

a = 5;
b = 6;
c = a + b;

Ожидаете ли вы, что a или b станет 11 после суммы?(что произойдет, если вы выбрали вариант 2 или 3).Конечно, вы не можете перегрузить operator+ для int, но это просто и интуитивно понятный пример.


Одно улучшение производительности: в вашем варианте 1 вместо

MyClass operator+(MyClass rhsObj)

Я бы использовал

MyClass operator+(const MyClass& rhsObj)

Таким образом, вы избежите одной дополнительной копии + вы скажете «клиенту», используя ваш код, что вы не изменили rhsObj вообще, но просто используйте его значение.

4 голосов
/ 06 ноября 2011

Вы действительно хотите варианты один и три здесь.

Пользователи MyClass будут ожидать, что он будет следовать Принципу наименьшего удивления , и никогда не ожидают увидеть правую часть, измененную в результате сложения. Использование const more обеспечит это, а также послужит документацией. Если вы хотите изменить левую сторону, используйте +=. Вот так:

// Plus: Modify neither the left nor the right
//--------------
MyClass operator +(const MyClass& rhsObj) const
{
    return MyClass(myInteger + rhsObj.myInteger, myDouble + rhsObj.myDouble);
}

// Increment: Modify the left
//--------------
MyClass& operator +=(const MyClass& rhsObj)
{
    myInteger += rhsObj.myInteger;
    myDouble += rhsObj.myDouble;

    return *this;
}

Демо: http://ideone.com/8oarA

4 голосов
/ 06 ноября 2011

Между этими тремя + *

есть тонкие различия. Первый вариант:

// Variation - 1
//--------------
MyClass operator+(MyClass rhsObj)
{
    return MyClass(this->myInteger + rhsObj.myInteger, this->myDouble + rhsObj.myDouble);
}

принимает в качестве входных данных объект MyClass, что означает копию rhsObj передается в +, оставляя исходный объект rhsObj без изменений.Это переопределение возвращает вновь созданный объект MyClass.

Второй вариант:

// Variation - 2
//--------------
MyClass & operator+(MyClass & rhsObj)
{
    rhsObj.myInteger = this->myInteger + rhsObj.myInteger;
    rhsObj.myDouble = this->myDouble + rhsObj.myDouble;

    return rhsObj;
}

принимает ссылку на rhsObj в качестве входных данных, а rhsObj обновляется в методе.

Последний вариант

// Variation - 3
//--------------    
MyClass & operator+(MyClass & rhsObj)
{
    this->myInteger = this->myInteger + rhsObj.myInteger;
    this->myDouble = this->myDouble + rhsObj.myDouble;

    return *this;
}

также принимает ссылку на rhsObj в качестве параметра, но rhsObj не изменяется внутри метода.Вместо этого обновляется объект MyClass, для которого вызывается +.

2 голосов
/ 06 ноября 2011

Концептуально, вы хотите вернуть новую пару, так что в вашем случае первый вариант, возможно, лучше.

Или, возможно, вы хотите вернуть один из аргументов, но тогда я нахожу запутанным имя оператора. Может быть лучше += для третьего варианта.

0 голосов
/ 06 ноября 2011

Я бы подумал, что вариант 1 будет лучше по большей части по одной причине: если бы у вас было только утверждение lhs + rhs;, ожидали бы вы / хотите, чтобы lhs или rhs были изменены?Я знаю, что, вероятно, не смогу в большинстве (всех?) Случаях.

Поэтому это исключает варианты 2 и 3.

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