技术交流QQ群:1027579432,欢迎你的加入!
1.Cpp中的引用
- 引用变量是一个别名,即它是某个已经存在变量的另一个名字。一旦把引用初始化为某个变量,就可以使用该引用名称或变量名称来指向变量。
2.Cpp中的引用VS指针
- 引用与指针之间的区别:
- 不存在空的引用,引用必须要连接到一块的合法内存
- 一旦引用被初始化为一个对象,就不能被指向另一个对象,指针可以在任何时候指向到另一个对象
- 引用必须在创建时被初始化,指针可以在任何时间被初始化。
3.Cpp中创建引用
-
可以把变量名称想象成为变量附属在内存位置的标签,可以把引用当成是变量附属在内存位置的第二个标签。因此,可以通过原始变量名称或引用来访问变量的内容。如下面的例子:
int i = 7; int &r = i; // r是一个初始化为i的int型引用 double &s = d; // s是一个初始化为d的double类型引用
- 具体的程序实例如下:
// 声明简单变量 int i; double d; // 声明引用变量 int &r = i; // 与int r = i;的区别是内存的分配,后者会再分配一个内存空间 double &s = d; i = 5; cout << "i = " << i << endl; cout << "i的引用是: " << r << endl; cout << "i的地址是: " << &i << endl; cout << "r的地址是: " << &r << endl; d = 11.7; cout << "d = " << d << endl; cout << "d的引用是: " << s << endl; /*注意与上面的对比不同*/ int x; int y = x; x = 6; cout << "x = " << x << endl; cout << "y = " << y << endl; cout << "x的地址是: " << &x << endl; cout << "y的地址是: " << &y << endl;
4.Cpp中的引用作为参数
-
引用通常用于函数参数列表和函数返回值,两者的区别是:
- 4.1 引用作为函数参数
- 引用作为函数参数,C++之所以增加引用类型,主要是把它作为函数参数,以扩充函数传递数据的功能。C++中函数传递参数的几种方法:
- 将变量名作为实参和形参。这时传给形参的是变量的值,传递时单向的。如果在执行函数期间形参的值发生变化,并不传回给实参。因为在调用函数时,形参和实参不是同一个存储单元。
- 传递变量的地址。形参是指针变量,实参是一个变量的地址。调用函数时,形参(指针变量)指向的是实参变量的内存单元,这种通过形参指针可以改变实参的值。
- C++提供了传递变量的引用。形参是引用变量,和实参是一个变量。调用函数时,形参(引用变量)指向实参变量的内存单元,这种通过形参引用可以改变实参的值。
void swap(int &x, int &y){ int temp; temp = x; x = y; y = temp; } // 引用作为函数参数 int a = 100; int b = 200; cout << "没有交换前a,b的值分别是: a = " << a << ",b = " << b << endl; swap(a, b); cout << "交换后a,b的值分别是: a = " << a << ",b = " << b << endl;
- 4.2 引用作为函数的返回值
- 通过使用引用来代替指针,会使C++程序更容易阅读和维护。C++函数可以返回一个引用,方法与返回一个指针类似。当函数返回一个指针时,则返回一个指向返回值的隐式指针。这样,函数就可以放在赋值语句的左边,见下面的例子:
// 引用作为函数的返回值 double &setValues(int i, double *arr){ return arr[i]; } double vals[] = {10.1, 12.6, 3.14, 24.1, 50.5}; cout << "数组没改变前的值: " << endl; for (int i = 0; i < 5; i++) cout << "vals[" << i << "] = " << vals[i] << endl; cout << "数组改变后的值: " << endl; setValues(1, vals) = 20.23; // 改变数组的第2个元素 setValues(3, vals) = 78.99; // 改变数组的第4个元素 for (int i = 0; i < 5; i++) cout << "vals[" << i << "] = " << vals[i] << endl;
- 注意:当返回一个引用时,要注意被引用的对象不能超过作用域。所以,返回一个对局部变量的引用是不合法的,但是,可以返回一个静态变量的引用!
int & func(){
int q;
return q; // 在编译时报错
static int x;
return x; // 安全,x在函数作用域外仍然是有效的
}
- 引用作为函数返回值,其他注意地方:
- 以引用返回函数值,定义函数时需要在函数名前加&
- 用引用返回一个函数值的最大好处是:在内存中不产生被返回值的副本
- 引用作为返回值时,必须遵守下面的规则:
- 不能返回局部变量的引用。主要原因是局部变量会在函数返回后被销毁,因此被返回的引用就成了"无所指"的引用,程序会进入未知状态。
- 不能返回函数内部new分配的内存的引用。虽然不存在局部变量的被动销毁问题,可对于这种情况下(返回函数内部new分配内存的引用),又会面临其他尴尬局面。例如,被函数返回的引用只是作为一个临时变量出现,而没有被赋予一个实际的变量,那么这个引用所指向的空间(由new分配)就无法释放,造成内存泄漏。
- 可以返回类成员的引用,但是最好是const。主要原因是当对象的属性是与某种业务规则相关联的时候,其赋值常常与某些其他属性或者对象的状态有关,因此有必要将赋值操作封装在一个业务规则当中。如果其他对象可以获得该属性的非常量引用(指针),那么对该属性的单纯赋值就会破坏业务规则的完整性。
5.C++中的引用类型总结
-
引用:就是变量的一个别名,作为别名来说,一个变量不能只有别名,而没有自己的真实姓名。
- 5.1 基本数据类型的引用
int a = 3; int &b = a; // b就是a的引用,即b是a的一个别名;引用必须初始化,否则会编译错误 b = 10; cout << "a = " << a << endl; // 此时a的值已经由原来的3变成了10,因此对别名b做任何操作,其实质都是对变量a本身做操作!
- 5.2 结构体类型的引用
typedef struct{ int age; char name; double salary; }Student; void print_info(){ Student s1; // 定义一个结构体变量,s1 Student &s = s1; // 给s1起了一个别名叫s s.age = 20; // 通过引用给结构体变量的数据成员赋值 s.name = 'A'; cout << "s.age = " << s.age << ", s.name = " << s.name << endl; } print_info() // 调用上面的函数
- 5.3 指针类型的引用
- 指针类型的引用是当中最复杂的,最难理解的,同时在写法上也不一样。定义:
类型 *&指针引用名 = 指针;
- 参见下面的实例:
// 指针类型的引用 int m = 10; // 定义一个整型的变量a int *p = &m; // 定义一个指向变量a的指针p int *&p_reference = p; // 定义指针p的引用p_reference即是p的别名 *p_reference = 20; // 把20赋值给*p_reference,相当于把20赋值给*p,也就是相当于把值赋值给a cout << "m = " << m << endl;