• C++ Primer笔记002:引用/指针/const


    1. 引用

    1.1 引用不是对象或变量

    引用就是对象或变量的别名,但引用不是对象或变量

    int a=10;
    int &b=a;

    这里面,b就是变量a的另一个名字,对b操作就是对a操作,对a操作,b也会变化

    void testreference()
    {
    	int a=10;
    	int &b=a;
    	b=5;
    	cout<<a<<b<<endl;
    	a=4;
    	cout<<a<<b<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    1.2 引用必须初始化

    因为引用一定是某个变量的别名,引用一定是和变量绑定在一起的,所以引用必须初始化

    int a=10;
    int &b; <---错误

    在这里插入图片描述

    1.3 不能定义引用的引用

    因为引用不是对象,但是引用又要绑定一个对象,所以不能定义引用的引用

    int a=10;
    int &b=a;
    int &(&c)=a; <---错误

    在这里插入图片描述

    1.4 引用类型要适配

    因为操作引用就是操作变量或者对象本身,所以对于内置类型,变量和其引用之间的类型要适配。

    int a=10;
    float &b=a; <---错误

    在这里插入图片描述

    1.5 非const引用不能绑定字面值

    因为引用必须和变量进行绑定,所以非const引用不能绑定字面值

    int a=10;
    int &b=20; <---错误

    在这里插入图片描述

    所以,引用的基本特性就五个:

    1.不是对象;
    2.必须初始化;
    3.不能定义引用的引用;
    4.类型适配;
    5.不能绑定字面值.
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2. 指针

    2.1 指针和引用的区别

    指针就是变量的地址,可以通过引用访问变量,也可以通过指针访问变量,但是指针是对象,而引用不是,这是二者的根本区别

    void testpointer()
    {
    	int a=10;
    	int *p=&a;
    	int *q;
    	cout<<p<<endl<<q<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    通过上述代码,可以知道,指针可以不初始化(只是为了演示,不要这样做),但是引用必须初始化

    另外,&符号既能表示引用,也是取地址符号,当&出现在=左侧时,是引用,在=右边就是取地址

    2.2 指针的指针

    因为指针是一个对象,所以可以定义指针的指针,但是不能定义引用的引用

    void testpointer()
    {
    	int a=10;;
    	int *p=&a;
    	int *q;
    	int **pp = &p;
    	cout<<p<<endl<<q<<endl;
    	cout<<pp<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    所以,指针的引用的不同点就是:

    1.引用必须初始化,指针不用,
    2.可以定义指针的指针,但是不能定义引用的引用,这两点的原因就是指针是变量,而引用不是(只是个别名)
    
    • 1
    • 2

    2.3 类型一致

    指针所指向的数据的类型要和指针的类型一致

    float a=10;
    int *p=&a;
    
    • 1
    • 2

    在这里插入图片描述

    2.4 指针的引用

    因为指针是对象,引用不是,所以可以定义指针的引用,但是不能定义引用的指针

    void testpr()
    {
    	int i=0;
    	int *pi=&i;
    	int *&pr=pi;
    	cout<<pr<<endl<<pi<<endl;
    	*pr=4;
    	cout<<i<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

    int *&pr=pi;说明了如何定义一个指针的引用,可以从右向左读。
    先看pr部分,我们知道有个对象叫pr;接着看到&pr,我们知道pr是一个引用
    最后看到int *,就知道这个引用和一个int类型的指针绑定,这个指针就是pi
    因为pr是pi的别名,所以对可以通过pr改变i。

    2.5 void 型指针

    void型指针可以存放任意类型的指针(包括二级指针),但是不能对void型指针解引用,所以void*指针可以保护数据所在的内存不被修改

    void testvoidp()
    {
    	double d=1.2;
    	double *pd=&d;
    	int i=11;
    	int *pi=&i;
    	void *vp=pi;
    	vp=pd;
    	cout<<__func__<<endl;
    	cout<<*vp;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    3. const

    3.1 const的基本作用

    之前所讲的C++中的变量值,都是可以赋值的,如果我们不允许对变量赋值,那么就要将变量设置为const。

    void testconst()
    {
    	const int c=10;
    	c=20;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    在这里插入图片描述

    可见,只能对const变量进行初始化,不能对其赋值,因为const变量的值不能被改变

    3.2 对const变量的引用

    可以用const来修饰一个引用,称为对const变量的引用,对const变量的引用不能直接修改所绑定的对象(这个性质通常用于函数传参,使传的参数在函数中不能被改变)

    void testconst()
    {
    	int i=2;
    	const int &ri=i;
    	ri=3;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述也就是说,无法通过ri来修改i的值

    3.3 不能把一般引用与const变量进行绑定

    因为const的变量无法修改,所以不能把一般引用const变量进行绑定

    void testconst()
    {
    	const int c=10;
    	int &ri=c;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果可以通过一般引用来绑定const的变量,那么就可以通过该引用修改const变量,与const的属性相冲突,所以,不能用一般引用与const变量进行绑定。
    在这里插入图片描述

    3.4 const变量的引用可以绑定字面值

    一般的引用不能与字面值进行绑定,但是const变量的引用可以绑定字面值(因为有const修饰)。而且,const变量的引用不仅可以绑定字面值,还可以绑定一般的对象(允许类型不匹配)

       void testconst()
       {
       	double d=1.2;
       	const int &rc=10;
       	const int &rc1=d;
       	cout<<rc<<endl<<rc1<<endl;
       }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    正是因为const变量的引用几乎可以绑定任何对象,所以函数的参数一般都设定为const变量的引用,扩大了函数可传参数的范围

    此外,由于是按引用传参,所以避免了拷贝,加快了代码的执行速度。

    当执行const int &rc1=d;时,rc1并不是真正的和d绑定,而是绑定了一个临时变量,编译器会把这句代码转化成下面这样

    const int tmp=d; //类型转换 double to int
    const int &rc1=tmp;

    在这种情况下,引用绑定的是一个临时量对象不是d本身,而是临时变量tmp

    c++认为,常量引用可以绑定这个临时量,而普通引用就不能绑定这个临时量。因为c++认为,使用普通引用绑定一个对象,就是为了能通过引用对这个对象做改变。如果普通引用绑定的是一个临时量而不是对象本身,那么改变的是临时量而不是希望改变的那个对象,这种改变是无意义的。所以规定普通引用不能绑定到临时量上。

    那么为什么常量引用就可以呢,因为常量是不能改变的。也就是说,不能通过常量引用去改变对象,那么绑定的是临时量还是对象都无所谓了,反正都不能做改变,也就不存在改变无意义的情况。

    所以,常量引用可以绑定临时量,也就可以绑定非常量的对象、字面值,甚至是一般表达式,并且不用必须类型一致。

    3.5 不存在const引用

    4.因为引用并不是对象,所以不存在const引用(注意理解const变量的引用和const引用的区别)

    void testconstreference()
    {
    	double d=1.2;
    	int  &const rc=10; //const的引用
    	const int &rc1=d;
    	cout<<rc<<endl<<rc1<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    const变量的引用与一般引用(见C++知识点——指针、引用基础)的区别

    1.一般引用不能绑定字面值。但是const变量的引用就可以	
    2.一般引用要与绑定的数据的类型一致,但是const变量的引用是个例外
    
    • 1
    • 2

    4. const与指针

    4.1 const变量的值不能改变

    const变量的值不能改变,所以想要存放const变量的地址,就需要使用指向const变量的指针。

    void testconstpointer()
    {
    	const int i=0;
    	const int *pi=&i;
    	cout<<pi<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    4.2 const变量的指针可以存储非常量的地址

    所以指向const变量的指针的基本作用就是存储const变量的地址,而且const变量的指针也可以存储非常量的地址(类型要匹配),因为pi本身是变量pi本身并不是const

    void testconstpointer()
    {
    	int i=0;
    	const int *pi=&i;
    	cout<<pi<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    4.3 const常量的存储地址

    const变量i的地址不能使用指向非常量的指针来存储,而且非常量的指针也不能指向常量的指针,否则可以通过指针修改const变量。

    void testconstpointer()
    {
    	const int i=0; 
    	const int *pi=&i; //对
    	int *p=&i; //错,p不是常量指针
    	cout<<pi<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    =======================================

    void testconstpointer()
    {
    	const int i=0;
    	const int *pi=&i;
    	int *p=&pi;
    	cout<<pi<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    在这里插入图片描述

    4.4 const指针

    因为引用不是对象,但是指针是对象,所以存在const指针

    void testconstpointer()
    {
    	int i=0;
    	const int *const pi=&i;
    	cout<<pi<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述

    const int *const pi;的读法依然采用从右向左的读法

    先看到pi,我们知道这是一个变量,接着看到const,我们知道他是一个const变量,然后看到*,我们知道这个是const的指针变量,看到const int我们知道这个const指针指向一个const int

    因为pi用const修饰,所以pi中存储的地址值不能改变,也就是说,pi本身不能改变

    void testconstpointer()
    {
    	int i=0;
    	int j=0;
    	const int *const pi=&i;
    	pi=&j;
    	cout<<pi<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    因为pi指向const int,所以不能通过pi来改变指向的对象的值。

    void testconstpointer()
    {
    	int i=0;
    	int j=0;
    	const int *pi=&i;
    	*pi=10;
    	cout<<pi<<endl;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

  • 相关阅读:
    代理IP与Socks5代理在多领域的卓越应用
    k8s 资源注册表
    代码随想录 Day-44|#70 爬楼梯(进阶)|#322 零钱兑换|#279 完全平方数
    多进程与多线程 - 概述
    电脑基础知识-电脑不认新硬盘时该怎么办?
    第1章 基于.Net(Core)框架Web程序的IIS部署发布
    GAMES104-现代游戏引擎 1
    PAN3020 Sub-1G无线收发芯片
    LeetCode【65. 有效数字】
    学习自定义SpringBoot Starter组件 (超详细的图文教程,从理论到实战)
  • 原文地址:https://blog.csdn.net/jiangchufeng123/article/details/133958546