引用定义:
1.引用是c++对c的重要扩充,是变量的一个别名,c++中&定义引用:类型 & 引用名 = 被引用对象
2.引用是别名,在声明的时候必须初始化,在实际的代码中主要用做函数的形参,作为目标的别名而使用
int a;
int &b = a;
引用特点:
1.引用是别名,在声明的时候必须初始化
2.在实际的代码中主要用做函数的形参,引用作为目标的别名而使用,并且引用声明完毕后,相当于目标变量名有两个名称,即该目标原名称和引用名,且不能再把该引用名作为其他变量名的别名
3.对引用的修改,相当于对目标的修改
4.引用与原变量共享相同的值和地址
5.&在此不是求地址运算,而是起标识作用
6.引用本身不是一种数据类型,因此引用本身不占存储单元,系统不给引用分配存储单元。对引用求地址,就是对目标变量求地址。&b与&a相等
7.不能建立数组的引用。因为数组是一个由若干个元素所组成的集合,所以无法建立一个数组的别名
例1:
#include <iostream>
using namespace std;
int main(int argc, char *argv[])
{
int a = 10;
int &b = a;
cout <<r <<" " << a<<endl;
b = 20;
cout <<r <<" " << a<<endl;
return 0;
}
结果10 10 和20 20
例2:
1.
int *a = nullptr;
int * &ptr = a; //ok,表示int*的引用ptr初始化为a
int b = 10;
ptr = &b; //ok, ptr是a的别名,是一个指针
2.
void &a = 3; //error, 不合法的
//void只是在语法上相当于一个类型,本质上不是类型,没有任何一个变量或对象,其类型为void
3.
int a[10] = {0};
int &b[10] = a; //error,不能建立一个引用类型的数组
4.
int a;
int &b = a;
int & *ptr = &b; // error,企图定义一个引用的指针
为什么用引用:
c
1.按值传递,如果有很大的数据项,复制数据需要很长的时间,出现性能问题
(当然可以使用指针可避免)c++:
1.按值传递
2.按引用传递,避免复制大量的数据开销,提高性能
引用和指针的差别:
引用:引用就是变量的一个别名,操作和对变量直接操作一样
指针:利用地址,直接指向存在存储器中的另一个地方的值。通过指针可以找到以它为地址的内存单元
1. 指针有自己的空间,引用只是别名
2.sizeof指针是4,引用为对象实际大小
3.指针可以初始化为null,引用必须是一个已有对象,有空指针没有空引用,每一个引用都是有效的
4.指针和引用的++运算不同
5.返回动态内存分配的对象或内存,必须使用指针,引用可能内存泄漏
6.指针是变量,可以把指针再次赋值指向别处,而引用是别名,在建立的时候必须初始化,并且不会再关联其他不同的变量
7.由于指针也是变量,可以有指针变量的引用,但void引用不合法
8.引用的参数传递:传递引用给函数和传递指针给参数的效果是一样的。但是引用作为参数比指针有更清晰的语法
按值传递,按引用传递和按指针传递的区别
按值传递: 不对变量修改
按引用传递:对引用的修改和对原值修改是一样的
按指针传递:指针对值的修改,原值也会修改
例:
#include <iostream>
using namespace std;
//按值传递
void A(int val)
{
val = 10;
}
//按引用传递
void B(int& val)
{
val = 10;
}
//按指针传递
void C(int *pval)
{
*pval = 10;
}
int main(int argc, char *argv[])
{
int a = 1,b = 1,c = 1;
A(a);
B(b);
C(&c);
cout <<a <<" " <<b<<" "<<c <<endl;
return 0;
}
输出结果:
a = 1,b= 10, c= 10
解析:
- A:按值传递,a的值相当于传递堆栈上的一个副本,函数传递结束只是对副本进行了修改,在调用完foo后的a的值还是1
- B:按引用传递,对引用的修改和对原值修改是一样的
- C:按指针传递是,指针对值的修改,原值也会修改
常引用:
定义:不希望通过引用来改变原始变量的值时
const 类型标识符 & 引用名 = 被引用的变量名
int a = 10;
const int &b = a;
b = 20;
a = 20;
编译报错,b试图修改a的值,虽然常引用无法修改原始变量的值,但仍然可以通过原始变量自身来修改原始变量的值。
为什么使用引用参数?
在C系列语言中,函数只能返回一个值,但程序需要返回两个值怎么办?
解决方案之一:用引用给函数传递两个参数,然后由函数往目标中填入正确的值。
函数返回值时,要生成一个值的副本,而引用返回值的时候不需要生成副本,所以提高了性能。
注意:
如果返回不在作用域内的变量或者对象的引用就有问题了,这与返回一个局部作用域指针的性质一样严重。
因为,当函数调用完成,局部变量就会被销毁。而此时我们若将局部变量的值通过引用返回拷贝给目标变量的时候,有可能会出现在拷贝之前局部变量已经被销毁,从而导致目标变量获取不到返回值。
普通的传值返回则不存在这样的问题,因为编译器会将返回值拷贝到临时存储空间后再去销毁局部变量的。
虽然这种情况在一些编译器中并没有发生,但在设计程序的时候也应该尽量避免这一点。
1.
int res = 0
int& func (int a)
{
res = a * a;
return res; //ok,返回引用,res的值在函数的作用域之外
}
2.
int& func (int a)
{
int res = 0;
res = a * a;
return res; //error,返回局部变量的引用
}
int main()
{
int &val = func(5); // error,返回的引用是个局部变量,当程序结束以后,会自动销毁(堆栈)
return 0;
}