在C++中当布尔式的真值能够确定时,不再考虑该布尔式尚未检验的部分。如:

if(a > 0 || b < 0) return 0;

(A)如果a = 3,那么当判断到a>0后,就确定该布尔式是真,于是就进入下一句,而不再考虑b<0的真值。

当然,C++允许用户量身打造属于自己的 && 和 || 操作符,额……,对,就是重载工作。

但是,一旦你重载了上述操作符,那么属于它们的(A)语义也就会被取代。

考虑下面的这种情况,姑且记为(情况1):

	int *p;
	//... ...
	if(p!=nullptr && (&p) == 3)
	{
		//DO Something... ...
	}

在(A)语义中,如果p为空指针,当判断到p!=nullptr时,就会结束该布尔式的判断,

因此,不会造成"&p"对空指针取值的情况。

然而,一旦重载了&&和||操作符,(A)则会被下面“函数调用的语义“代替。

一般来讲,如果你写下了这样的句子:

if(exp1 && exp2) ... ...
编译器会视作以下两者之一:

其一: 

if(exp1.operator&&(exp2)) ... ...

其二:
if(operator&&(exp1, exp2)) ... ...
这看起来貌似没什么不对? = =!


然而,重载之后遵循的“函数调用”语义和原本遵循的(A)语义有两大重要区别:

1、当函数调用动作被执行,所有的参数值都必须评估完成。也就是在“函数调用”语义下,

即使p == nullptr ,(情况一)也会执行(&p)操作,从而评估参数(&p) == 3的情况。毫无疑问,这是不合理的。

2、C++语言规范并没有明确定义函数调用动作各参数的评估顺序,所以没有办法知道exp1和exp2孰先孰后。

这就和(A)语义固定从左往右的评估方式形成了鲜明的对比。毋庸置疑,未经过重载的(A)语义更理想。


综上所述,请不要重载&&和||操作符。


逗号(,)操作符有着类似的情况。

表达式中如果含有逗号操作符,那么就会有这样的情况:

x = exp1, exp2;

先计算逗号左边的表达式exp1,然后再计算逗号右边的表达式exp2,

最后整个逗号表达式的返回值是右边的表达式exp2的返回值。


因此,重载逗号操作符也会出现重载&&和||操作符同样的后果,所以,还是不要觊觎重载逗号操作符吧。