时间:2014.03.11
地点:基地二楼
---------------------------------------------------------------------
一、简述
C++中譬如 && 和 || 等运算符和C一样,执行短路运算,或骤死式评估方式,即一旦该表达式的真假值确定,即使表达式中还有部分尚未检验,整个评估工作已经结束。比如:
char *p;
...
if( (p!=0)&&(strlen(p)>10) ...
这里无需担心调用strlen时p是否为null指针,因为p是否为0这部分检测如果是否定的,strlen已经不会发生调用,整个表达式真假已经确定,这种骤死式的评估方式对于 && 运算符同样适用。
---------------------------------------------------------------------
二、&& 和 || 重载问题
C++允许为用户定制类型量身定做 && 和 || 操作符,即运算符重载的方式,如果你这么做,那么这种骤死式的游戏规则将会打破,重载后相当于是函数调用,不再具备上述语义,程序逻辑会发生改变。函数调用式语义和骤死式语义的区别是:
1.函数调用动作被执行时,所有参数值都必须先评估完成再工作,于是在调用重载后的 && 和 || 时,参数的合法性已经完全确立。
2.C++规范并未标明函数调用中各参数的评估顺序,谁先谁后不确定。而骤死式评估法总是由左向右对表达式进行评估。
因此,如果你对 && 和 || 进行重载,就不会再拥有某些预期的功能,所以建议不要重载 && 和 ||
---------------------------------------------------------------------
三、逗号(,)操作符重载问题
逗号也是一个操作符,特别是在for循环更新区中最常用。比如将字符串反转函数:
void reverse(char s[]){
for(int i=0,j=strlen(s)-1;i<j;++i,--j){
int c=s[i];
s[i]=s[j];
s[j]=c;
}
}
这里就用到了逗号操作符,因为for循环的最后一个成分必须是表达式,使用个别语句比如分号形式改变i和j的值是不合法的。且C++规定,表达式如果含逗号,那么逗号左侧会先被评估,右侧后评估,最后这个表达式的结果以逗号右侧的值为代表。所以上述整个逗号表达式首先评估++i,然后评估--j,而整个逗号表达式的结果是 --j的返回值。
---------------------------------------------------------------------
四、立场
知道这些运算符是可重载后,重载运算符必须模仿这些行为,但不幸的是你无法执行也无必要执行这样的模仿。假如重载操作符为普通函数,此时因为两个表达式都当做函数调用的参数,所以无法保证评估顺序。而即便你将操作符重载为成员函数也还是无法保证这种从左到右的骤死式评估方式,于是,不要去重载具有这类特征的运算符。
以下列出不能重载的操作符
. (点号) .* (点号+星号) :: (域运算符) ?:
new delete sizeof typeid
static_cast dynamic_cast const_cast reinterpret_cast (四大cast-四大类型转换符)
而能重载的操作符有:
operator new operator delete operator new[] operator delete[] //new 和 delete加上operator后都能重载了
各类算术运算符和逻辑运算符和位运算符和比较运算符,简写运算符可重载
++ -- , -> ->* () []
记住:重载运算符的目的是让程序更容易被阅读、被撰写、被理解,如果没有好的理由这么做不要去做,特别是 && || ,实在没有什么好处,所以几乎别考虑重载。