欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++ 引用

程序员文章站 2022-05-13 21:17:17
...

文章概述

  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;
}

输出结果:
C++ 引用
为什么会出现这个结果? 对于变量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;
}

输出结果:
C++ 引用
我们发现输出结果正常,所以我们有下面的结论:
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;
}

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


指针的引用以及常量引用

(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;
相关标签: 引用