鱼C论坛

 找回密码
 立即注册
查看: 2418|回复: 5

[学习笔记] 025-C++之引用

[复制链接]
发表于 2018-8-26 20:40:21 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
本帖最后由 moc 于 2018-8-26 22:25 编辑

1、引用的概念
引用是C++的概念,在C中没有引用这个东东,它属于C++编译器对C的扩展。
引用的定义:
                Type &name = var;
        int a = 10;
        int &b = a;
        b = 20;
        cout << a << endl;  // 20 
        int &c = b;   
        c = 30;
        cout << a << endl;  //30 
        int d = c;
        d = 50;
        cout << a << endl;  //30 
引用可以看成是一个已经定义好的变量的别名。
引用在定义的时候必须为它绑定变量,而且一旦定义完成,便无法为它重新绑定到另一个的变量。
上面程序中,b、c都是a的引用变量,通过b、c都可以间接修改a的值,可以把b、c看成a的别名。
2、引用的意义
1.引用作为其他变量的别名,可以通过它来间接修改变量的值,在一些场合可以代替指针的存在。
2.引用相较于指针具有更好的可读性和实用性。
360截图20180826204234525.jpg
通过引用做函数参数,在被调函数中间接修改变量的值,相较于指针可读性更强。
3、引用变量占据内存空间吗?
通过在结构体中定义引用变量来测试:
struct Teacher
{
        int &a;
        int &b;
        char &c;
        double &d;
};

int main()
{
        cout << sizeof(Teacher) << endl;   // 16
        system("pause");
        return 0;
}
可以发现引用本身占据一定的内存空间,具体来说是不管什么类型的引用都占4个字节(32位机),和指针一样。
4、引用的本质
1.引用在C++的内部实现是一个常量指针。
即:     Type &name   <----->   Type* const name;
2.C++编译器在编译过程中使用常量指针来作为引用的内部实现,它占4字节(32位机)内存空间,一旦初始化后就不能绑定其他变量(常指针其值不能修改,即指向关系不能修改),初始化之后的使用,C++编译器一旦看到是引用变量,便会自动帮我们做*p的操作,这就是我们能用引用间接赋值的原理,同样当我们对引用变量取地址时,C++编译器不会对这个这个常指针取地址,而是把它的值直接输出,即变量的地址。

3.从使用的角度,引用会让人误会其只是变量的一个别名,没有自己的存储空间。这只是C++为了实用性而做出的细节隐藏
360截图20180826211931596.jpg
4.引用与间接赋值的三个条件
        ①定义两个变量(一个实参、一个形参)
        ②建立关联 => 实参取地址传给形参
        ③形参通过*p操作去间接修改实参的值
对于引用做函数参数,其实质就是把①放在主调函数中,②③放入被调函数中,且由C++编译器帮我们做了取地址和*p操作。
5、返回引用的函数
函数返回引用时可以看做就是把返回的变量转成(绑定自身)引用变量,再返回
        当函数的返回值为引用时,若函数返回的时栈(局部)变量,不能将其作为其他引用的初始值。
        若返回引用时,为静态(static)变量或全局变量时,这该函数即可做左值也可做右值。
int& myf()  //返回引用,即返回a的地址,引用在使用时会自动做*操作。
{
        int a;
        a = 12;
        return a;
}
void main08()
{
        int b1 = myf();      // 使用引用,(隐式*p操作)  
        int &b2 = myf();   // b2引用初始化, 对返回的引用a取地址,引用a取地址,是其绑定的内存地址

        cout << b1 << endl;     //12
        cout << b2 << endl;    // 乱码
        system("pause");
}
上面在引用b2初始化时绑定临时变量a,在函数mf()调用结束后,a所在的内存空间被销毁,所以b2会乱码。
6、指针的引用
相当于给指针取别名,和上面的是一样的,不要被其形式所迷惑。
struct AdvTeacher
{
        char name[32];
        int age;
};
// 结构体变量指针的引用
// p2是t2的别名
void getTeacher(AdvTeacher * &p2)
{
        p2= (AdvTeacher *)malloc(sizeof(AdvTeacher));
        p2->age = 30;
}
int main()
{
        AdvTeacher *t2 = NULL;
        getTeacher02(t2);  // 在被调函数中给t2分配空间
        t2->age = 10;

        system("pause");
        return 0;
}
7、常引用
C++可以声明const 引用:
        const Type &nmae = var;           //本质 const Type* const name
声明常引用让该引用变量拥有只读属性,也即通过引用变量将不能修改其绑定变量的值,但变量可以通过自身来修改。
        int b = 10;
        const int &a = b;   // 本质const int* const a
        // a = 11;   // error 不能通过常引用a去间接修改b的值
        b = 12;   // 本身可以修改
给字面量初始化const引用:
//int &c = 13;   // error 字面量不可初始化引用
const int &c = 13;   // 字面量可以初始化常引用
        当使用字面量对const引用进行初始化时,C++编译器会为该常值量分配空间,将引用名作为这段空间的别名。
        字面量const引用相当于一个只读变量。
       





本帖被以下淘专辑推荐:

想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2018-8-26 20:56:21 | 显示全部楼层
C++引用相当于是个隐形的指针吧。
不过在一些特殊场合不如指针强大
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-26 22:18:49 | 显示全部楼层
无符号整形 发表于 2018-8-26 20:56
C++引用相当于是个隐形的指针吧。
不过在一些特殊场合不如指针强大

它的本质就是一个常指针,较指针也更加安全,其功能自然较指针也受到限制。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-26 22:28:54 | 显示全部楼层
moc 发表于 2018-8-26 22:18
它的本质就是一个常指针,较指针也更加安全,其功能自然较指针也受到限制。


但是比如一颗特殊的树(比如像html树),把它定义成一个类,子标签用sublabels成员来表示
假如你有一个指针(这个指针不是C语言里面的指针),比如{1,2,3},就是指向第一个顶层标签的第二个子标签的第三个子标签的话,编写一个通过这个指针去修改树中元素的函数,除非吧Sublabels成员改成一个引用,否则根本用引用写不出来,因为引用变量必须在定义的时候初始化。
这时指针就可以大显身手了,可以像一根真正的针一样扎进复杂的树,精准地指向你需要的元素。
C/C++之美——指针
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2018-8-26 22:44:29 | 显示全部楼层
无符号整形 发表于 2018-8-26 22:28

但是比如一颗特殊的树(比如像html树),把它定义成一个类,子标签用sublabels成员来表示
假如你有 ...

你这个比喻挺有意思的,我想也正是由于指针这种可以想怎么指就可以怎么指,导致了许多安全问题,才使得许多高级语言舍弃了指针,都改为用引用, java中就 只有引用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2018-8-27 08:51:13 | 显示全部楼层
moc 发表于 2018-8-26 22:44
你这个比喻挺有意思的,我想也正是由于指针这种可以想怎么指就可以怎么指,导致了许多安全问题,才使得许 ...

这确实很好用,在一个html树里面通过“指针”({1,2,3})再通过引用修改是不可能的。(因为引用会修改到自身,而且引用无法改变绑定对象,这是最不好的一点)。
真的,只有写多了程序,才能体会到C/C++之美。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-24 22:02

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表