我应该使用哪种C ++运算符重载变体?而且,为什么?

时间:2011-11-06 08:31:03

标签: c++ operator-overloading

这里给出了加法运算符(+)的重载的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;
}

Assignment Operator(=)应该是什么情况?应该使用哪种变体?

5 个答案:

答案 0 :(得分:10)

取决于您的需求。

首先,关于你的版本 - 显然是

  • “Variation - 1”创建新对象,而不触及两个操作数。
  • “Variation - 2”将结果存储在第二个操作数
  • “Variation - 3”将结果存储在“this”的第一个操作数中。

最有可能的是,Variation - 1是最受欢迎的。

为什么呢?因为副作用。如果您看到如下表达式:

a = b + c;

无论abc的类型是什么,您会怎么想?我认为,abc的总和,bc未被触及,我的意思是 - 旧的价值观。 /> 例如,假设:

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

您希望ab在总和之后成为11吗? (如果您选择变体2或3,则会发生这种情况)。当然,你operator+不能重载int,但这只是一个简单而直观的例子。


一项绩效改进:在您的变体1中,而不是

MyClass operator+(MyClass rhsObj)

我会用

MyClass operator+(const MyClass& rhsObj)

通过这种方式,您可以避免使用一个额外的副本+您将使用您的代码告诉“客户”,您根本不会更改rhsObj,而只是使用其值。

答案 1 :(得分:4)

这三个+之间存在微妙的差异

第一个变体:

// 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的{​​{1}}对象已更新。

答案 2 :(得分:4)

你真的想要一个三个的变体。

MyClass的用户希望它遵循The Principle of Least Astonishment,并且永远不会期望看到由于添加而修改了右侧。使用const更多将强制执行此操作,并将用作文档。如果您想修改左侧,请使用+=。像这样:

// 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

答案 3 :(得分:2)

从概念上讲,您希望返回一对新对,因此在您的情况下,第一个变体可能更好。

或许您想要返回其中一个参数,但后来我发现混淆了运算符的名称。第三种变体可能更好+=

答案 4 :(得分:0)

我认为变体1最好是主要原因之一:如果你只有lhs + rhs;语句,你会期望/想要lhsrhs被修改吗?我知道在大多数(所有?)情况下我可能都不会。

因此,排除了变体2和3。