C++小白到大白养成记 - 养成记5:引用的本质分析

--事物的难度远远低于对事物的恐惧!

    在上一节中我们知道,引用是变量的别名,操作这个别名就相当于操作这个变量,而在C++中,引用更多时候可以在一些场合代替指针,并且相对指针来说,引用具有更好的可读性和实用性。

    下边来看看一个老生常谈的交换函数

#include <iostream>

using namespace std;

//引用方式
void swap1(int& a, int& b)    //注意:函数参数中的引用不需要初始化
{
    int tmp = a;
    a = b;
    b = tmp;
}
//指针方式
void swap2(int* a, int* b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

int main(int argc, char const *argv[])
{

    int a1 = 12;
    int b1 = 23;
    int a1 = =12;
    int b2 = 23;

    swap1(a1, b1);
    cout << "a1 = " << a1 << ", " << "b1 = " << b1 << endl;

    swap2(&a2, &b2);
    cout << "a2 = " << a2 << ", " << "b2 = " << b2 << endl;

    return 0;
}

编译输出如下,可以看到,两个函数均正确的交换了变量值,从使用角度来说,引用更令人感到简洁愉快。

下边我们来看看特殊的引用

const引用
    -C++中申明的const引用让引用这个变量拥有只读属性(注意是引用这个变量,不能通过引用这个变量修改内存空间的值,但是还是可以通过用来初始化引用的那个变量去修改)
    -格式为:const Type& name = value;

    int a = 12;
    const int& b = a;
    int* p = (int*)&b;

    // b = 0;  //error, 引用b为只读变量
    a = 23; 
    cout << a << endl;
    
    *p = 34;
    cout << a << endl;
编译输出如下:

    -当用常量对const引用进行初始化时,C++编译器会为常量分配空间,并把引用名作为这段空间的别名
    

#include <iostream>

using namespace std;

int main(int argc, char const *argv[])
{
    const int& value = 1;
    int *p = (int *)&value;

    // value = 12; //error,value为只读变量
    *p = 34;

    cout << "&value = " << &value << endl;
    cout << "value = " << value << endl;
 
    return 0;
}

编译输出如下,可以看到,C++编译器已经为value分配了内存空间,同时可以通过指针修改这段内存空间的内容:

结论:使用常量初始化const引用,生成的是一个只读变量。

一个问题:引用有自己的存储空间吗?

#include <iostream>

using namespace std;

struct TRef
{
    char& r;
};

int main(int argc, char const *argv[])
{
   
    cout << "sizeof(TRef) = " << sizeof(TRef) << endl;
    cout << "sizeof(char*) = " << sizeof(char*) << endl;
    return 0;
}
编译执行下上边的代码(我的g++为64为编译器)

从输出结果来看,引用的大小跟指针的大小一样。

本质就是:引用在C++中的内部实现是一个指针常量

    

注意:
    -C++编译器在编译过程中用指针常量作为引用的内部实现,因此引用所占用的内存空间大小与指针相同。

    -从使用角度,引用只是一个别名,C++为了实用性而隐藏了引用的存储空间这一细节。
    -函数不能返回局部变量的引用(类似于返回局部变量的指针)

引用的意义:可在大多数情况下代替指针,又能避免由于指针操作不当带来的内存错误。

总结:
    -引用作为变量别名而存在大多数情况是为了代替指针
    -const引用可以使得变量具有只读属性
    -引用在编译器内部使用指针常量实现
    -引用的最终本质为指针,占用的内存空间与指针大小相同
    -引用可以尽可能的避开内存错误

猜你喜欢

转载自blog.csdn.net/lms1008611/article/details/80554352