1 运算符的重载

其实从一开始我们就已经见过运算符的重载了,例如,运算符*用于地址,就可以得到存储在这个地址中的值;用在两个数字上时,得到的是乘积的效果。

重载运算符需要使用被称作运算符函数的特殊函数形式,其格式如下

operator op(argument-list)

operator +() 重载+运算符,operator *()重载*运算符。

通过一个重载的示例来了解,现有一个Box类,为它定义一个operate+()成员函数来重载+运算符,以便实现两个对象的长宽相加。

class Box{
public:
    int length;
    int width;

    Box operator+(const Box& box1){
        Box box;
        box.length=this->length+box1.length;
        box.width=this->width+box1.width;
        return box;
    }
};

如果box2box3sum都是类对象,就可以编写这样的等式:

sum=box2+box3;

//编译器行为
sum=box2.operator+(box3);

可见重载的目的就在于改变其内部操作的效果,但要注意像运算符优先级这种是无法改变的。

2关联性与优先级

在一般表达式中先运行优先级高的运算符,再运行优先级低的运算符,比如a+b*c先运行乘法再加法,但我们可以用()将a+b关联起来先运行。运算符的优先级有很长一串,很多时候不可能完全记住,C++Primer在这一方面的建议是:当你拿捏不准时,通通用括号来实现你想要的运算顺序

3 注意事项

1.不建议在同一个表达式中改变它的值还同时引用它,这样做不仅使代码的可读性变差,而且容易出错。
比如

int i=0;
cout<<i<<" "<<++i;

编译器会发出警告Unsequenced modification and access to 'i',因为它不知道是该先输出还是先进行++的操作。

为了增加我们对这一点的印象,再观察这样一个示例:

string s="helloworld";

auto beg = s.begin();
while(beg!=s.end()){
   *beg = toupper(*beg++);
}

在这个大小写转换的代码中,我们希望先进行*beg = toupper(*beg),再进行beg++的操作。但是由于我们在同一句话里使用且改变beg,编译器很有可能会先进行beg++的操作,再进行*beg = toupper(*beg)

  1. ||、&&

对于这两个操作符有一个特别的点就是,如果前半部分已经满足/不满足条件,那么操作符后面的部分将不再进行判断,比如对于a||b,如果已经知道a的值判断为1,那么无论b是0还是1都不会对最终的结果产生影响,同理对于a&&b,如果已经知道a的值判断为0,那么b无论是1还是0都对最终的结果没有影响。

  1. 执行顺序

编译器可以确保表达式中的运算优先级,但是不会保证它的执行顺序,比如

g()+f()*m()-n();

在这样的式子里编译器不会确保先调用哪个函数,如果在这几个函数里有些有关联的话,比如说m()函数依赖于g()函数得到的某个值,那么建议最好分开写,在获得每一个函数的返回值后再进行最终的运算。