C++:引用、指针与const

1. 引用

引用即绑定到另一个对象上,因此定义了一个引用,对其操作即是对与之绑定的对象进行操作(如为引用赋值,获取引用的值,以引用作为初始值...)。

  • 定义引用时是绑定对象,因此必须在定义引用同时必须初始化
  • 引用本身不是对象,只是另一个对象的别名,因此不能定义引用的引用,也不能定义引用的指针。
  • 引用本身非对象,因此不能进行赋值和拷贝,一旦定义了引用,其只能绑定这个对象,无法再绑定别的对象。但一个对象可以定义多个引用。
  • 引用的类型要与之绑定的对象严格匹配(不支持类型转换),并且引用只能绑定在变量/对象上,不能绑定字面值或者表达式上(即形参为string &str;时,必须使用变量初始化,“hello word”初始化将编译出错)。——两个例外情况

2. 指针

与引用类似,实现对对象的间接访问。

  • 指针允许在定义时进行初始化,此时将执行默认初始化。
  • 指针本身是对象,因此可以定义指针的引用,可以对指针赋值和拷贝(对指针赋值即是存放新的地址,指向新的对象),因此在其生命周期内可以先后指向不同对象。并且一个对象可以定义多个指针。
  • 初始化为空指针,即不指向任何对象。(int *p=0;或者int *p=nullptr;均可以。  但是int i=0; int *p=i; 不是初始化空指针语句。)
  • 指针类型和它指向的对象类型必须严格匹配(不支持类型转换),并且指针只能指向变量/对象,不能指向字面值或者表达式。——两个例外情况
指针和引用的本质区别:

引用不是对象,指针本身即是对象。

指针和引用的共同:

都需要类型和对象类型严格匹配(不支持类型转换),并且指针只能指向变量/对象,不能指向字面值或者表达式。同时,也都对常量指针和常量引用出现例外情况,即这两种情况下可以使用一般的初始化。

指针值(前三种有效):
  • 1.指向一个对象;
  • 2.指向末尾的下一个位置;
  • 3.空指针,即指针不指向任何对象;
  • 4.无效指针。
注意:

1、试图拷贝或者以其他形式访问一个无效指针将引发错误,访问无效指针的后果无法预计,并且编译器不检查此类错误,在设计程序时,必须清楚所有指针的有效性;

2、第2和3种指针虽然有效,但并不指向任何具体对象,因此访问此类指针的对象也不允许。

因此:建议初始化所有指针,并且尽量在定义了对象之后,再定义对象的指针。如若不清楚指针的指向,可以暂时初始化为nullptr或0 ,此时编译器即可以知道所有指针的指向。

指针作为条件判断:

前提:指针有效。

如if(p)...      空指针,条件为0;其他有效指针,条件为1 。

如if(*p)...     表示指针指向的对象作为条件判断。

比较两个指针是否相等。相等情况有三:都为空指针;都指向同一对象;都指向同一对象的下一个地址。

3. const 限定符

普通类型限定:

const只是个限定符,限定了不能改变其值,此限定只在要改变const变量的值时才起作用。

  • const对象一旦创建即不能改变其值,因此const对象必须在定义时初始化(普通初始化——直接、隐式、表达式、常值、变量
  • const限定只在改变其值时限制,对其他操作并不影响。因此和普通初始化相同,可以用变量、常量初始化,也可以进行隐式地类型转换。同时也可以拷贝const对象,并赋值给常量对象或者变量对象(因为对变量的拷贝不会改变对象的值,赋值会改变对象的值)
定义并初始化一个const变量,则编译器会在整个文件中将所有用到const对象替换成其初始值。
  • 即使用常量初始值代替const对象
  • 多文件使用const对象,需要在声明和定义中都加extern关键字

3.1 const 与引用

const int ci=2017;

const int &ri=ci;

  • 对常量的引用可以绑定常量和非常量,但是const限定了 不能通过引用改变其绑定对象的值,但可以通过别的方式改变对象的值(直接给对象赋值,或者定义一个新的普通引用)。
  • 当然,无论是加不加const,都可以使用解引用或者用引用直接赋值等普通操作(如 int i1 = 0; const int &ci = i1;  int i2 = ci; 可以用常量引用给普通变量赋值)。
引用中的一种例外:
  • 对常量的引用,在初始化时允许使用任意表达式作为初始值,只要该表达式能转换成引用的类型(常量int)即可。——也即可以进行普通初始化,即 允许常量引用绑定 非常量的对象、字面值或者一般表达式,且允许发生隐式转换。
  • (因为 对常量的引用 只是限定了不能通过引用改变绑定对象,并没有限定对象本身是不是一个常量,也没有限定不能通过其他方式改变对象的值)
注释:

对常量的引用可以普通初始化,可以绑定非常量,但常量对象必须用对常量的引用绑定(但常量对象可以赋值给常量或变量对象)。

3.2 const 与指针

  • 指针可以指向常量和非常量,但是const限定 不能通过指针改变其所指对象的值,但可以通过别的方式改变对象的值。
  • 当然,无论是加不加const,都可以使用解引用等普通操作,但不能把存放了 指向常量的指针 赋给另一个普通指针(int i = 0;  const int *pi1 = &i; int *pi2 = pi1;)。
指针中的一种例外:
  • 指向常量的指针,可以指向一个非常量对象。
  • (因为 指向常量的指针 只是限定了不能通过指针改变对象的值,但没有规定对象本身是不是一个常量,也没有限定不能通过其他方式改变对象的值)
注释:

指向常量的指针 可以指向非常量(普通初始化),但要存放常量的地址必须使用 指向常量的指针。

指针和引用对于const的区别:常量指针(也是普通类型限定)

(1)指针是对象,引用不是对象,因此允许把指针定义为常量,即常量指针。

  • 常量指针必须初始化,初始化完成后,不能改变指针的值,即不能改变指针的指向地址。(和普通限定下的对象一样,可以用常量指针赋值给常量或变量指针,且是普通赋值)
  1. 变量地址存储为常量指针  int errNumb=0;  int *const curErr=&errNumb;
  2. 常量地址存储为指向常量的常量指针 const double pi=3.14;  const double *const pip =π
  • 而能不能改变常量指针指向的变量的值,完全依赖于对象的类型。
(2)引用和指针操作不同,引用相当于绑定对象的别名(对对象的直接访问),指针是存放对象的地址(解引用,为间接访问)。
  • 因此引用“ 无论是加不加const,都可以使用用引用实现直接赋值等普通操作,因为此时相当于使用了对象(如 int i1 = 0; const int &ci = i1;  int i2 = ci;编译通过, 可以用常量引用给普通变量赋值)。
  • 而指针“ 无论是加不加const,都可以使用解引用等普通操作,但不能把存放了 指向常量的指针 赋给另一个普通指针(int i = 0;  const int *pi1 = &i;  int *pi2 = pi1;编译出错,不能用 const int * 初始化 int *)。
注释:

对const的引用和指向常量的指针都是对引用和指针的限定,不能通过引用或指针方式改变对象的值。

而常量指针,const限定的是变量类型,和前边的const限定符一样,即不能改变变量的值,在常量指针下,即是不能改变指针的指向。

3.3 顶层const和底层const:

实际上是对 非常量引用、非常量指针、普通类型限定(包括常量指针)、对const的引用、指向const的指针 初始化和赋值的总结。

但是对于引用和指针的使用,不通过绑定或指针改变对象的值,因此可以进行普通赋值和解引用操作 或 其他改变对象值的操作。(如 const int & ci=i1;  int i2=ci; 此处是使用引用操作,而不是绑定常量对象)

  • 顶层const:作用于对象本身的 const,即对变量const;对指针本身const(常量指针)
  • 底层const:对引用和指针的限定
对象拷贝操作时,顶层和底层const区别比较大:
  • 顶层的const作用于对象本身,即是普通的类型限定,因此定义时必须初始化,且支持普通初始化——直接、隐式、表达式、常值、变量,也即支持用顶层const对象初始化。而顶层const当然可以作为被拷贝对象,因为拷贝不会改变对象的值(如 const int i1= 's' ;  int i2=i1;)。
  • 底层const作用于引用和指针限定,即是 对常量的引用 和 指向常量的指针。因此常量对象只能用 对常量的引用 或者 指向常量的指针 绑定或者存储;而 对常量的引用 和 指向常量的指针 可以 绑定或者指向 非常量对象(即引用和指针的例外情况),但非常量引用或指针不能绑定或指向常量对象(因为引用和指针要求类型严格匹配)。



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值