小知识 ——引用
概念:某个函数或变量的别名
和指针的区别:
引用和函数或者变量共享一块内存,在定义时必须初始化,一旦和变量或函数绑定便不可以更改。
指针:有自己的内存空间,可以指向空,可以在任何时候改变指向的变量。
引用的例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 3 using namespace std; 4 5 int main () 6 { 7 // 声明简单的变量 8 int i; 9 double d; 10 11 // 声明引用变量 12 int& r = i; 13 double& s = d; 14 15 i = 5; 16 cout << "Value of i : " << i << endl; 17 cout << "Value of i reference : " << r << endl; 18 19 d = 11.7; 20 cout << "Value of d : " << d << endl; 21 cout << "Value of d reference : " << s << endl; 22 23 return 0; 24 }
把引用作为参数,用引用来调用函数:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 using namespace std; 3 4 // 函数声明 5 void swap(int& x, int& y); 6 7 int main () 8 { 9 // 局部变量声明 10 int a = 100; 11 int b = 200; 12 13 cout << "交换前,a 的值:" << a << endl; 14 cout << "交换前,b 的值:" << b << endl; 15 16 /* 调用函数来交换值 */ 17 swap(a, b); 18 19 cout << "交换后,a 的值:" << a << endl; 20 cout << "交换后,b 的值:" << b << endl; 21 22 return 0; 23 } 24 25 // 函数定义 26 void swap(int& x, int& y) 27 { 28 int temp; 29 temp = x; /* 保存地址 x 的值 */ 30 x = y; /* 把 y 赋值给 x */ 31 y = temp; /* 把 x 赋值给 y */ 32 33 return; 34 } 35 当上面的代码被编译和执行时,它会产生下列结果:
交换前,a 的值: 100
交换前,b 的值: 200
交换后,a 的值: 200
交换后,b 的值: 100
- 局部变量的引用和指针不可以做返回值
- 使用引用来代替指针会使c++程序更容易阅读和维护。返回引用和返回指针的方法类似
- 函数返回引用时返回一个指向返回值的隐式指针,这样可以放在赋值语句左边
例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 3 using namespace std; 4 5 double vals[] = {10.1, 12.6, 33.1, 24.1, 50.0}; 6 7 double& setValues( int i ) 8 { 9 return vals[i]; // 返回第 i 个元素的引用 10 } 11 12 // 要调用上面定义函数的主函数 13 int main () 14 { 15 16 cout << "改变前的值" << endl; 17 for ( int i = 0; i < 5; i++ ) 18 { 19 cout << "vals[" << i << "] = "; 20 cout << vals[i] << endl; 21 } 22 23 setValues(1) = 20.23; // 改变第 2 个元素 24 setValues(3) = 70.8; // 改变第 4 个元素 25 26 cout << "改变后的值" << endl; 27 for ( int i = 0; i < 5; i++ ) 28 { 29 cout << "vals[" << i << "] = "; 30 cout << vals[i] << endl; 31 } 32 return 0; 33 }
当上面的代码被编译和执行时,它会产生下列结果:
改变前的值
vals[0] = 10.1
vals[1] = 12.6
vals[2] = 33.1
vals[3] = 24.1
vals[4] = 50
改变后的值
vals[0] = 10.1
vals[1] = 20.23
vals[2] = 33.1
vals[3] = 70.8
vals[4] = 50
引用作为返回值,必须遵守以下规则:
- (1)不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成为了"无所指"的引用,程序会进入未知状态。
- (2)不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况(返回函数内部new分配内存的引用),又面临其它尴尬局面。例如,被函数返回的引用只是作为一 个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成memory leak。
- (3)可以返回类成员的引用,但最好是const。主要原因是当对象的属性是与某种业务规则(business rule)相关联的时候,其赋值常常与某些其它属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其它对象可以获得该属性的非常 量引用(或指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
* 返回一个引用时要注意被引用的对象不能超出作用域。所以返回一个对局部变量的引用是不合法的但是可以返回一个对静态变量的引用。
例如:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int& func() { 2 int q; 3 //! return q; // 在编译时发生错误 4 static int x; 5 return x; // 安全,x 在函数作用域外依然是有效的 6 }
常引用:为了提高效率的同时保护函数中的数据不会改变
非const引用只能绑定到该引用同类型的变量,const引用可以绑定到不同但相关类型的对象,或绑定到右值。
例子:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 double dval = 3.14159; 2 //下3行仅对const引用才是合法的 3 const int &ir = 1024; 4 const int &ir2 = dval; 5 const double &dr = dval + 1.0;
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int iv = 100; 2 int *&pir = &iv;//错误,非const引用对需要临时对象的引用 3 int *const &pir = &iv;//ok 4 5 const int ival = 1024; 6 int *&pi_ref = &ival; //错误,非const引用是非法的 7 const int *&pi_ref = &ival; //错误,需要临时变量,且引用的是指针,而pi_ref是一个非常量指针 8 const int * const &pi_ref = &ival; //正确 9 //补充 10 const int *p = &ival; 11 const int *&pi_ref = p; //正确
const &引用名 = 目标变量名
这种方式声明的引用,不能通过引用对变量的值进行修改,但是目标自身仍然可以修改,这是语言的不一致性。测试:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 int &p1 = 20;//错误 2 3 const int &p = 30; 4 5 double dvalue = 3.14; 6 int &pd = dvalue; 7 8 double value2 = 3.14;
身体是1,财富·名利·是0,没有1有再多的0都没有用!!