引用的概念
引用(&)就是给一个已经定义的变量取了一个别名。 就像包谷是玉米的另一种称呼,苞米也是玉米的一种称呼。 如何使用引用?
类型 + & + 引用变量名 = 引用实体;
例如:
int a = 8;
int& b = a;
虽然变量名不一样,但是都是同一块内存空间。
需要注意:引用时的类型必须与引用实体的类型一致。
引用的特性
- 引用在定义的时候必须使用合法的实体进行初始化。
- 一个实体可以被引用多次,但是一旦引用了一个实体,那么就不能再引用其他的实体。
int main(void)
{
int a = 0;
int& c = a;
int& d = a;
int& e = a;
int i = 2;
c = i;
return 0;
}
c相当于是变量a这块内存空间的别名,如果我们给c修改值,也就是相当于给变量a这块内存空间修改值,所以此时a的值为2.
引用在函数中的使用
引用在函数中一般用于作参数和作返回值。
void Swap(int& x1, int& x2)
{
int tmp = x1;
x1 = x2;
x2 = tmp;
}
如果在这里单纯的使用传值传参,那么Swap函数的形参只是单纯将a和b的内容作了一份拷贝,a、b的内存空间和形参的内存空间不是同一块,因此改变形参并不能改变a、b。而使用引用,x1、x2的内存空间此时就是a、b的内存空间,此时改变形参则可以改变实参。
int& Count()
{
static int n = 0;
n++;
return n; }
我们来回顾一下这种形式的函数返回值
由于调用函数会建立栈帧,函数执行完之后就会释放栈帧。如果调用该函数,当该函数执行完之后才会进行返回,但是此时函数执行完了函数栈帧已经被释放,意味着返回值已经被释放,那么该返回什么呢? 其实返回值已经被存储在建立的临时变量里了,返回的是临时变量里的数据。 这是从我曾经的一篇博客里截来的,这里我漏掉了一个知识点:如果返回的值特别大,这个临时变量则存储在调用该函数的函数栈帧内。 而如果使用引用作返回值
int& Add(int x1, int x2)
{
int ret = x1 + x2;
return ret;
}
int main(void)
{
int a = 1;
int b = 2;
int c = Add(a, b);
cout << c << endl;
return 0;
}
则不会产生临时变量来存储返回值。 但是对于上面的例子来说,存在一个非常大的问题: 而此时的解决方法就是引用c。
这样做的好处在于:
- a、提升了效率
- b、后期能够修改返回的内存空间的数据
【注意】 如果函数返回时,出了函数作用域,如果返回对象还未还给系统,则可以使用引用返回,如果已经还给系统了,则必须使用传值返回。
引用中的const
void ConstCiteTest()
{
const int a = 10;
const int& ra = a;
const int& b = 10;
double d = 12.34;
const double& rd = d;
}
int main(void)
{
ConstCiteTest();
return 0;
}
另外需要注意下面这个点,a并不是直接就截断然后就给变量i的,而是截断临时变量。 实际上临时变量也是具有常属性的。 所以,如果实际上引用的是临时变量,则需要使用const修饰,防止扩大权限。
引用与指针的区别
据调查,这是面试的时候经常被问到的一个面试题。 引用和指针的区别:
- 1.引用在定义的时候必须使用合法的实体初始化,而指针不强制。
- 2.引用在定义时引用了一个实体后就不能在引用其他的实体,而指针可以指向任意一个同类型的合法实体
- 3.引用在初始化时不能使用NULL初始化,而指针可以使用NULL。
- 4.引用加1指的是引用的实体加1,而指针加1指的是指针所指向的位置往后偏移一个同类型的大小
- 5.在sizeof中含义不同:引用结果为引用类型的大小,但指针始终是地址空间所占字节个数(32位平台下占4个字节)
- 6.访问实体方式不同,指针需要显式解引用,引用编译器自己处理
- 7.引用比指针使用起来相对更安全
|