20.C++- "&&","||"逻辑重载操作符的缺陷、","逗号重载操作符的分析
“&&”,”||”逻辑重载操作符的缺陷
大家,都知道“&&”,”||”拥有“短路”功能
- 比如a=(0&&b) : 由于第一个操作数为0,所以不会去判断b的内容,直接执行a=0
- 比如a=(-100||b): 由于-100不为0,所以不会去判断b的内容,直接执行a=1
可以参考下面代码:
int func(int i) { cout << "i = " << i << endl; return i ; } int main() { int a= (func(0)||func(100)); cout<<"a = " << a <<endl; return 0; }
运行打印:
i=0 a=0
并没有调用func(100)函数,同样”||”逻辑操作符也具有拥有“短路”功能
而在重载操作符下,“&&“,”||“就不会具备”短路”功能
参考以下示例:
class Test { int mValue; public: Test(int v) { mValue = v; } int value() const { return mValue; } }; bool operator && (const Test& l, const Test& r) //&&重载操作符 { return l.value() && r.value(); } Test func(Test t) { cout << "value()= " << t.value() << endl; return t; } int main() { Test t0(0); Test t1(1); int b= (func(t0)&&func(t1)); cout<<"b = " << b <<endl; }
打印:
value()=1 //进入func(t1) value()=0 //进入func(t0) b =0
从结果看出,调用了func(t0)和func(t1),并且调用顺序是从右往左的.
这是因为执行func(t0)&&func(t1)时:
编译器实际是执行的operator && (func(t0), func(t1))函数,所以需要进入func()初始化两个参数
然后通过下面代码, 发现参数初始化顺序是从右往左的:
int print(int t) { cout<<t<<endl; return t; } void func(int a,int b,int c) { } int main() { func(print(1),print(2),print(3)); return 0; }
运行打印:
“,”逗号重载操作符的分析
首先回顾下编译器自带的”,”逗号操作符
- 逗号表达式前N-1子表达式不需要返回值
- 逗号表达式从左往右计算,且最终的值等于最后一个表达式的值
比如:
int i=5,b=4; int a =(i++,i++,b+4,b=5,i++); // b=5,且a=(i++)=7,该行运行后,i便等于8 (i,b,a)=10; //a=10,i和b不变
- 逗号表达式,通过()圆括号来表示
比如:
int a[3][3]={ (1,2,3), (4,5,6), (7,8,9) }; //只初始化了a[0][0]=3, a[0][1]=6, a[0][2]=9
而在重载操作符下, “,”逗号就不会具备从左往右计算的功能了
重载逗号注意事项
- 尽量使用全局函数来重载
- 逗号重载函数的参数必须有一个是class类的类型 (让编译器知道这个,逗号是用户重载的)
- 逗号重载函数的返回值类型必须是引用(因为有可能要对返回值进行运算)
- 逗号重载函数的返回值必须是最后一个参数的值(“,”逗号操作符的特性)
参考以下示例
#include <iostream> #include <string> using namespace std; class Test { int mValue; public: Test(int i) { mValue = i; } int value() { return mValue; } Test operator +(int i) //重载 + 逗号操作符 { Test ret=this->mValue +i; cout<<ret.mValue<<endl; return ret; } }; Test& operator , (const Test& a, const Test& b) //重载 ,逗号操作符 { return const_cast<Test&>(b); } int main() { Test t1(0); Test t2(5); Test t3=(t1+1,t2+1);return 0; }
运行打印:
6 //从最右侧执行t2+1 1 //最后执行t1+1
和之前分析的”&&”,”||”逻辑重载操作符缺陷一样:
编译器实际是执行的operator , (t1+1, t2+2)重载操作符函数.
由于初始化参数的顺序是从右往左初始化的,所以执行顺序变反了,先执行t2+2.
总结:
其实使用编译器自带的”,”逗号操作符,用在对象上也能成功,因为“,”主要就是用来隔离代码运行,并返回最后一个参数的值.不会参与对象的运算.
所以在以后的开发中,不要重载”,”逗号操作符