1. 逗号操作符(,)
(1)逗号表达式用于将多个子表达式连接为一个表达式
(2)逗号表达式的值为最后一个子表达式的值
(3)逗号表达式的前N-1个子表达式可以没有返回值,最后一个要有返回值
(4)逗号表达式按照从左向右的顺序计算每个子表达式的值
exp1,exp2,exp3,…,expN;
1 #include <iostream> 2 3 using namespace std; 4 5 void func(int i) 6 { 7 cout << "func(): i = " << i << endl; 8 } 9 10 int main() 11 { 12 #include <iostream> 13 14 using namespace std; 15 16 void func(int i) 17 { 18 cout << "func(): i = " << i << endl; 19 } 20 21 int main() 22 { 23 int a[3][3] = { 24 25 (0, 1, 2), //注意这里是逗号,不是花括号 表达式值:2 26 27 (3, 4, 5), //相当于只给数组前三个元素赋值 表达式值:5 28 29 (6, 7 ,8) //分别是2、5、8,其余为0 表达式值:8 30 }; 31 32 /* int a[3][3] = { 这才是初始化 33 34 {0, 1, 2}, 35 36 {3, 4, 5}, 37 38 {6, 7 ,8 } 39 };*/ 40 41 int i = 0; 42 int j = 0; 43 44 while (i < 5) 45 46 func(i), //这里与下一行的i++组合一个表达式 47 48 i++; //所以while不会死循环 49 50 等价于while(i < 5) 51 { 52 func(i); 53 i++; 54 } 55 56 57 for (int i = 0; i < 3; i++) 58 { 59 for (int j = 0; j < 3; j++) 60 { 61 cout << a[i][j] << endl; //2,5,8,0,0,0,0,0,0 62 } 63 } 64 65 (i, j) = 6; //合法:逗号表达式返回j,相当于j = 6 66 67 cout << "i = " << i << endl; //5 68 69 cout << "j = " << j << endl; //6 70 71 72 73 return 0; 74 75 } 76 77 int i = 0; 78 int j = 0; 79 80 while (i < 5) 81 82 func(i), //这里与下一行的i++组合一个表达式 83 84 i++; //所以while不会死循环 85 86 等价于while(i < 5) 87 { 88 func(i); 89 i++; 90 } 91 92 93 for (int i = 0; i < 3; i++) 94 { 95 for (int j = 0; j < 3; j++) 96 { 97 cout << a[i][j] << endl; //2,5,8,0,0,0,0,0,0 98 } 99 } 100 101 (i, j) = 6; //合法:逗号表达式返回j,相当于j = 6 102 103 cout << "i = " << i << endl; //5 104 105 cout << "j = " << j << endl; //6 106 107 108 109 return 0; 110 111 }
运行结果:
2. 重载逗号操作符
(1)在C++中重载逗号操作符是合法的
(2)使用全局函数对逗号操作符进行重载
(3)重载函数的参数必须有一个是类类型(因为这里指的是类的操作符重载)
(4)重载函数的返回值类型必须是引用
ClassType& operator ,(const ClassType& a, const ClassType& b) 全局函数进行重载
{
return const_cast<ClassType&>(b); //逗号表达式,返回右操作符,必须强制转换,函数返回值是引用,所以去除const属性
}
1 #include<iostream> 2 #include<string> 3 4 using namespace std; 5 6 //重载需要类类型,定义类 7 class Test 8 { 9 int mvalue; 10 public: 11 Test(int i) 12 { 13 mvalue = i; 14 } 15 int value() 16 { 17 return mvalue; 18 } 19 }; 20 21 //全局函数进行逗号操作符重载 22 Test& operator , (const Test& a, const Test& b) // 1、参数必须有一个为类类型 23 { 24 return const_cast<Test&>(b); //2,返回值是Test引用,所以要强制类型转换去掉const属性 25 } 26 27 Test func(Test& i) // 28 { 29 cout << "func() : i = " << i.value() << endl; 30 31 return i; 32 } 33 34 int main() 35 { 36 Test t0(0); 37 Test t1(1); 38 39 // Test tt=(t0,t1); //逗号表达式,等价于Test tt=t1; 40 41 //为什么先调用右边????逗号操作符重载中间发生变化,变成从右向左调用,违背逗号表达式 42 43 //因重载操作符的本质相当于函数调用,所以 44 45 //相当于Test tt = operator,(func(t0(0)), func(t1(1)));//函数调用! 46 47 //当进入函数体,参数的值必须被计算,而两个参数func(t0(0))和func(t1(1)) 48 49 //的计算次序是不确定的,在g++编译下,输出 50 51 //func(): i = 1 52 53 //func(): i = 0 54 55 Test tt = (func(t0), func(t1)); //逗号表达式,等价于Test tt=func(t1); 逗号表达式,本意是从左向右计算 56 57 58 59 // Test tt = (operator , (func(t0), func(t1))); //等价于Test tt = (operator , func(t0), func(t1)); 60 61 cout << tt.value() << endl; //1虽然结果是正确的,但中间的计算过程与 62 63 //逗号表达式原义从左向右计算要求有可能不一致。 64 65 return 0; 66 }
3. 重载时出现的问题与本质分析
(1)C++通过函数调用扩展操作符的功能
(2)进入函数体前必须完成所有参数的计算
(3)函数参数的计算次序是不定的
(4)重载后无法严格从左向右计算表达式,不重载时返回能从左向右,所以重载逗号操作符完全无意义,违背逗号表达式原生语义。
实验:工程中,完全没有必要重载逗号操作符
1 #include<iostream> 2 #include<string> 3 using namespace std; 4 //全局函数进行逗号操作符重载 5 6 class Test 7 { 8 int mvalue; 9 public: 10 Test(int i) 11 { 12 mvalue = i; 13 } 14 int value() 15 { 16 return mvalue; 17 } 18 }; 19 20 //不要进行逗号操作符重载 21 /* 22 Test& operator , (const Test& a, const Test& b) 23 { 24 return const_cast<Test&>(b); //返回值是Test 引用,所以要强制类型转换去掉const属性,用const_cast 25 } 26 */ 27 28 Test func(Test& i) 29 { 30 cout << "func() : i = " << i.value() << endl; 31 return i; 32 } 33 34 int main() 35 { 36 Test t0(0); 37 Test t1(1); 38 39 Test tt = (func(t0), func(t1)); 40 41 // Test tt = (operator , (func(t0), func(t1))); 42 43 cout << tt.value() << endl; //func(): i=0 44 //func(): i=1 45 46 去掉重载,结果与没有重载之前结果一致--------------工程中,完全没有必要重载逗号操作符 47 48 return 0; 49 }
4. 小结
(1)逗号表达式从左向右顺序计算每个子表达式的值
(2)逗号表达式的值为最后一个子表达式的值
(3)操作符重载无法完全实现逗号操作符的原生意义(从左向右计算)
(4)工程开发中不要重载逗号操作符