C++ 引用

文章概述

  1. 引用的定义以及格式
  2. 引用的初始化
  3. 引用的本质
  4. 函数的返回值是引用
  5. 指针的引用以及常量引用

引用的定义以及格式

a. 引用的定义: 对已定义的变量起的别名。定义引用的时候,必须绑定已定义好的变量。
b. 引用的格式: Type & name =var(已经定义好的变量);

int a =10;
int&b =a;

普通引用必须和绑定的对象的类型相同,(上面的就是普通引用)。操作引用和操作绑定的对象是一致的。


引用的初始化

引用可以分为普通引用和特殊引用。
a. 对于普通引用,定义的时候必须赋值,也就是初始化。
b. 作为函数的形式参数时,可以不进行初始化。

//普通引用
int a =10;
int&b =a;
//特殊引用(作为函数的形式参数)
void func(int& a)
{
  ...
}

引用的本质

引用的本质就是在C++内部的实现。首先分析下面对象的所占的内存空间:

struct StudentOne
{
   double a;
   int b;
}
StudentOne对象所占的内存空间是8+4=12(对于结构体字节对齐的问题已经考虑到)
struct StudentTwo
{
   double a;
   int b;
   int&c;
}
StudentTwo对象所占的内存空间是8+4+4=16(对于结构体字节对齐的问题已经考虑到)

我们知道引用是有自己的内存空间的。从我们使用角度,我们误以为引用是一个别名没有自己的内存空间,这是C++为了实用而作出的细节屏蔽。现在我们知道引用是有内存空间类似于指针。


int a =10;
int&b =a;

我们知道上面的代码是定义引用,引用的定义是不是和定义常量类似(const int a)。根据上面的两点,我们可以得出引用在C++的内部实现就是常量指针。
引用本质的结论: (1). 引用在C++中的内部实现是一个常量指针; (2). C++编译器在编译的过程中使用常量指针作为引用的内部实现,因此引用占用的内存空间与指针相同;(3). 从使用的角度来看,引用会让人误会其实是一种别名,没有自己的存储空间,这是C++为了实用性而做出的细节屏蔽。
下面的代码分析:

void func(int& a)
{
  a=5;
}

int main()
{
  int p =10;
  func(p);
}

调用函数 func(p)的时候,C++编译器会自动的取p得地址赋给a,不用我们手动的去地址。上面的函数func(int& a)内部实现就是下面:

void func(int * const a)
{
  *a=5;
}

我们知道调用这个函数时,C++编译器会自动将地址赋给a,不需要手动的取地址就OK了。


这里提下间接赋值,间接赋值的条件:
a. 定义两个变量(a,b)
b. 建立关联(将a的地址赋给b)
c. b可以间接的改变a的值
引用的应用场景: 其实把间接赋值成立的三个条件中的第二个和第三个写到一起,第一个单独在一起。


函数的返回值是引用

(1). 我们首先看返回值是普通变量:

int getA()
{
  int a=10;
  return a;
}

函数调用时,进入getA()的内部。C++编译器会给局部变量a分配一个内存空间。return a表示函数结束并且返回一个值给函数调用者。函数调用结束后,C++编译器将内存空间a的内容消除。
(2). 函数的返回值是引用:

int& getB()
{
  int a=10;
  return a;
}

函数调用时,进入函数内部。C++编译器会分配内存给a,注意: 返回的是变量a的地址以及a的值。(上面我们已经说过)
我们已经得知函数返回值是普通变量时,调用者只获得局部变量的值;函数返回值是引用时,调用者会获得局部变量的地址。
分析下面的代码a,b是否能够正常输出:

int& getB()
{
  int a=10;
  return a;
}
int main()
{
   int a =getB();
   int &b=getB();
   cout<<"a="<<a<<endl;
   cout<<"b="<<b<<endl;
   return 0;
}

输出结果:
这里写图片描述
为什么会出现这个结果? 对于变量a来说, 只是获得函数返回值的值也就是10。对于引用b来说,C++编译器会将调用函数中临时变量的地址返回给b,而临时变量的数据已经销毁,所以输出b不会得到我们想要看到的结果。
下面我们想如果调用函数中变量时全局变量或者是静态变量时,会发生什么?

int& getB()
{
  static int a=10;
  return a;
}
int main()
{
   int a =getB();
   int &b=getB();
   cout<<"a="<<a<<endl;
   cout<<"b="<<b<<endl;
   return 0;
}

输出结果:
这里写图片描述
我们发现输出结果正常,所以我们有下面的结论:
a. 当函数的返回值是引用时,若返回的是普通变量,则不能作为其他引用的初始值。
b. 当函数的返回值是引用时,若返回的是静态变量或全局变量时,能够成为其他引用的初始值。


我们分析一下,函数的返回值是引用时,能不能做为左值??换个说法就是成为左值得条件是什么??

int& getA()
{
    int a = 10;
    cout << a << endl;
    return a;
}

int& getB()
{
    static int a = 10;
    cout << a << endl;
    return a;
}
int main()
{
    getA() = 100;
    getA();
    cout << "--------------------" << endl;
    getB() = 100;
    getB();
    return 0;
}

输出结果:
这里写图片描述
对于这个结果产生的原因其实上面已经说了,引用返回调用函数中的地址。其实就在于变量的地址能够一直存在。我们可以得出下面的结论:
当函数返回值是引用时,若返回普通变量,它不能作为左值使用。但是,返回的是静态变量或者是全局变量时,可以作为左值使用。


指针的引用以及常量引用

(1). 指针的引用做形式参数格式: Type(数据类型)* &var,指针的引用做形式参数类似于二级指针。
(2). 常量引用:
a. 格式: const +数据类型 +var = 绑定的已定义的变量。
b. 常量引用的作用: 不能通过引用而改变绑定的变量的值。
c. 常量引用的初始化分为2种情况:

//1.通过已定义的变量初始化
int a =10;
const int&b =a;
//2.通过字面值常量初始化
const int&c =10;

我们先看下面的这两个问题?
(1). 普通引用可以用字面值常量初始化吗?
肯定是不可以的,字面值常量C++编译器没有分配内存空间。
(2). 为什么可以通过字面值常量初始化常量引用?

//C++编译器会给10分配内存空间,然后a指向这个内存空间。
const int& a=10;
//C++编译器将b放到符号表中
const int b=10;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值