引用的基本概念
引用不是新定义一个变量,而是给已存在变量取了一个别名,编译器不会为引用变量开辟内存空间,
它和它引用的变量共用同一块内存空间。
举个例子:你们村的村花叫李芳,她又是你的班长,她爸妈叫她小芳。
这时候村花,小芳,班长,就是同一个人,是李芳的别名。
这里 b和c就是引用,另外,引用和所要引用的变量应该是同种类型
引用的特性
1,引用在定义的时候必须初始化
int main()
{
int a = 10;
int& b; //这里不初始化就会报错
return 0;
}
2,一个变量可以有多个引用
int main()
{
int a = 10;
int& b = a;
int& c = b; //这里的b和c都是a的引用
return 0;
}
3,引用一旦引用了一个变量,就不能再引用其他的变量
int main()
{
int a = 10;
int& b = a;
int c = 20;
b = c; //这里就是把c的值赋值给b了
return 0;
}
如何理解常引用
首先说一下引用原则:对原引用的变量而言,权限只能不变或者缩小,不能变大
先要来一点铺垫
int main()
{
int a = 10;
double d = 2.2;
a = d; //double---->int 实际上发生截断,d本身不发生变化
cout << d << endl;
int c = 20;
double e = 5.5;
e = c; //int--->double 实际上发生了提升,c本身不变化
cout << c << endl;
return 0;
}
引用的权限问题
int main()
{
int a = 10;
int& b = a; //引用权限不变
const int& f = 10;
const int c = 10;
//int& d = c; //引用权限变大,报错
//int& e = 10; //对常量10引用,权限变大
int x = 10;
const int& y = a; //引用权限缩小
return 0;
}
看看下面这段代码,为什么报错呢? 因为int----->double。会发生提升,
创建一个临时变量,具有常性,而对于double的引用,这里相当于权限变大了
int main()
{
int a = 10;
//double& d = a; //这样报错是非常量限定
const double& c = a;
return 0;
}
引用的使用场景
1,做参数
//这里a是x的引用,b是y的引用
void Swap(int& a, int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int x = 10;
int y = 20;
Swap(x, y);
cout << x << " " << y << endl;
return 0;
}
2,做返回值
为什么引用可以用来做返回呢? 因为n是静态变量,出代码块(函数作用域)值不销毁
所以可以这样总结一下,当变量出函数作用域不销毁的时候,可以使用引用返回
如果出了作用域,值销毁,就不能使用引用返回,只能用传值返回
int& Count()
{
static int n = 0;
n++;
// ...
return n;
}
比较一下传值返回
关于传值和传引用的效率比较
这里就不说了,用脚都知道传引用效率高,因为传值为临时拷贝一份
引用和指针的区别
1,从语法的概念上来说,引用是变量的别名,不开辟空间。而指针存放的是变量的地址,大小是4/8个字节
2,从底层的角度来说,引用是按照指针的形势来实现的。
来看看底层的反汇编
引用和指针有什么不同点吗?
注意坑 : 引用传值, 指针传地址。 这句话是错误的, 因为引用的底层和指针是一样的。
所以引用是表明传值, 实际上还是传地址
1,引用没有对NULL引用,而指针有NULL指针
2,引用必须初始化,而指针不需要
3,指针有多级指针,而引用没有多级引用
4,引用一旦初始化就不能更改,而指针可以指向同类型的任意变量地址
5,sizeof求的是引用变量的类型大小,而指针求的是地址单元大小4/8
6,访问变量的时候,指针需要解引用,而引用编译器直接处理
7,引用+1就是变量的值加1,而指针加1就是向后走一个类型大小的偏移量
8,引用对于指针要安全一点