+=运算符重载

来源:互联网 发布:js 增加option 编辑:程序博客网 时间:2024/05/17 23:48
+=操作符的重载,使两个类的对象可以使用+=运算符来进行运算。其中要注意的是返回值为引用(&)的重要性。

要实现上面的需求,我们只需重载 operatpr+= 操作符即可,下面就是一个简单的示例,可以实现 c1+=c2的需求。

#include <iostream>using namespace std;class Complex{public:    Complex(float x, float y)        :_x(x), _y(y)     {        cout << "Complex contructor" << endl;    }        void display()    {        cout << "(x = " << _x << ", y = " << _y << ")" << endl;    }    void operator+=(Complex another)    {        this->_x += another._x;        this->_y += another._y;    }private:    float _x;    float _y;};int main(int argc, char* argv[]){    Complex c1(10.0, 15.0);    Complex c2(20.0, 25.0);    c1.display();    c2.display();    c1 += c2;    c1.display();    return 0;}

运算的结果如下:

(x = 10, y = 15) // c1(x = 20, y = 25) // c2(x = 30, y = 40) // c1 + c2

上面的代码实现了我们的简单+=需求,还有很多细节的地方没有考虑到,并且程序的运行效率也是有待优化的。首先我们先考虑以下情况。

C++关键字int类型创建的对象可以实现连等的操作,比如下面的例子;

int a = 10, b = 20, c = 30;a += b += c;cout << a << endl;cout << b << endl;cout << c << endl;

最终结果

605030

该表达式是从右向左依次执行的,首先计算 b+=c,结果b=50,c没有变动。然后计算a+=b,a=60,b=50。

如果我们要让类实现这样的功能,使用上面我们写好的代码可以成功吗?我们不妨测试一下,将main函数中的代码修改为如下的样子:

int main(int argc, char* argv[]){    Complex c1(10, 0);    Complex c2(20, 0);    Complex c3(30, 0);    c1 += c2 += c3;    c1.display();    c2.display();    c3.display();    return 0;}

此时再编译程序,你会发现出现了错误:

2015-05-17_224406

二进制“+=”: 没有找到接受“void”类型的右操作数的运算符(或没有可接受的转换),这句话是什么意思呢?我们分析一下程序的运算过程,一样是从右向左,相当于

c1.operator+=(c2.operator+=(c3))

首先是c2+=c3,在函数内部,我们给分别修改了 this->_x 和 this->_y的值,但此时你会发现,处理函数并没有返回任何值,这让接下来的 c1 与谁相加呢?这种情况下我们是不是要返回一个 Complex 的对象,才能使 c1 正常的与其相加,再次相加的过程会重复进入 operator+= 的重载函数中。所以,重载函数应该修改为如下的样子。

// 修改返回值为 Complex 对象Complex operator+=(Complex another){    this->_x += another._x;    this->_y += another._y;    // 将 this 指针解引用后返回    return *this;}

如上修改后,代码成功的运行了,我们得到了想要的结果:

(x = 60, y = 0) // c1.operator(c2.operator(c3))(x = 50, y = 0) // c2.operator(c3)(x = 30, y = 0) // c3

解决这个问题,我们只修改了函数的返回值,并在函数内部返回了解引用后的*this对象。这样就实现了连等的操作。接下来,我们继续考虑这样的情况。

在基础数据类型中,是允许出现这样的表达式的:

int a = 10, b = 20, c = 30;(a += b) += c;cout << a << endl;cout << b << endl;cout << c << endl;

运算的过程是,a首先与b结合,得到结果a=30,b未改变。随后得出的结果再与c结合,a+=c,结果a=60,c未改变。同样的案例,我们再次应用到我们自己重载的函数中试一下。将程序修改为如下的所示:

Complex c1(10, 0);Complex c2(20, 0);Complex c3(30, 0);(c1 += c2) += c3;c1.display();c2.display();c3.display();

运算后得出的结果是:

(x = 30, y = 0) // c1(x = 20, y = 0) // c2(x = 30, y = 0) // c3

这与上面基础数据类型运算出来的结果不一样啊,应该是 60 20 30 啊,怎么会变成这样的数据呢?我们细心来分析一下上面的案例,首先c1与c2先结合,c1+=c2后我们返回了*this,但返回值大家请注意,返回值并不是*this的引用,而是一份临时的对象与c3做了相加操作,最后临时对象销毁,而c1自身并没有参与到运算当中。所以最终得出的结果就是 30 20 30。那么想解决这个问题也非常简单,只需将返回值修改为Complex的引用即可,这样在c1与c2结合后得出的对象才是真正的c1,再与c3结合得出最终结果。

// 修改返回值为 Complex 对象的引用Complex& operator+=(Complex another){    this->_x += another._x;    this->_y += another._y;    // 将 this 指针解引用后返回    return *this;}

运算结果:

(x = 60, y = 0) //(c1 += c2) += c3(x = 20, y = 0) //c2(x = 30, y = 0) //c3

至此,+=运算符的重载我们就实现完毕了,几乎所有基本数据类型能实现的需求我们都实现了一遍,像-= *= /=运算符都与其类似。只需要按部就班的一步一步测试下来即可实现。

1 0