C++引用和const引用、常量指针、指针常量
1、引用、常量引用
引用主要被用做函数的形式参数--通常将类对象传递给一个函数.
引用在内部存放的是一个对象的地址,它是该对象的别名。引用不占用内存,因为取地址引用的值和被引用变量的地址相同。但是objdump –d xx底层编译器实现其实还是指针。
(1)引用必须初始化. 但是用对象的地址初始化引用是错误的,我们可以定义一个指针引用.
int ival = 1092; int &re = 1092; //错误。非常量引用的初始值必须为左值 int &re = ival; //ok int &re2 = &ival; //错误。不可用对象的地址初始化引用 int *pi = &ival; int *&pi2 = pi; //ok。可定义指针引用 int *&pi3 = &ival; //错误
(2)一旦引用已经定义,它就不能再指向其他的对象.这就是为什么它要被初始化的原因.
(3)const引用可以用不同类型的对象初始化(只要能从一种类型转换到另一种类型即可),也可以是不可寻址的值
double dval = 3.14159; //下3行仅对const引用才是合法的,对非const会编译错误 const int &ir = 1024; const int &ir2 = dval; const double &dr = dval + 1.0;
对于不可寻址的值,以及不同类型的对象,编译器为了实现引用,必须生成一个临时对象,引用实际上指向该对象,但用户不能访问它。所以上面的通过编译器转为:
//不可寻址,文字常量 int tmp1 = 1024; const int &ir = tmp1; //不同类型 int tmp2 = dval;//double -> int const int &ir2 = tmp2; //另一种情况,不可寻址 double tmp3 = dval + 1.0; const double &dr = tmp3;
(4)不允许非const引用指向需要临时对象的对象或值,即,编译器产生临时变量的时候引用必须为const(注意)
int iv = 100; int *&pir = &iv;//错误,非const引用对需要临时对象的引用 int *const &pir = &iv;//ok const int ival = 1024; int *&pi_ref = &ival; //错误,非const引用是非法的 const int *&pi_ref = &ival; //错误,需要临时变量,且引用的是指针,而pi_ref是一个非常量指针 const int * const &pi_ref = &ival; //正确 //补充 const int *p = &ival; const int *&pi_ref = p; //正确
********对于const int *const & pi_ref = &iva; 具体的分析如下:*********【仍需学习】
1.不允许非const引用指向需要临时对象的对象或值
int a = 2; int &ref1 = a;// OK.有过渡变量。 const int &ref2 = 2;// OK.编译器产生临时变量,需要const引用
2.地址值是不可寻址的值
int * const &ref3 = &a; // OK;
3.于是,用const对象的地址来初始化一个指向指针的引用
const int b = 23; const int *p = &b; const int *& ref4 = p; const int *const & ref5 = &b; //OK
const引用的语义:
试图通过此引用去(间接)改变其引用的对象的值时,编译器会报错。保证不会通过此引用间接的改变被引用的对象,但被引用对象还可通过别的方式改变其值。
与非常量引用区别:常量引用可读不可改,与绑定对象是否为const无关,可绑定到不同但相关的类型对象或左值。非常量引用可读可改,只可与非const对象绑定,只能绑定到与该引用同类型的对象。
2、常量指针、指针常量
常量指针:指向常量的指针,能通过常量指针读取内存中数据,但不可修改内存中数据
声明:const int * p; int const * p;
注:可以将一个常量的地址赋值给一个对应类型的常量指针,因为常量指针不能够通过指针修改内粗数据。只能防止通过指针引用修改内存中的数据,并不保护指针所指向的对象。
指针常量:指针本身是常量,其本身不可改变,即指向的位置不可改变,但其指向的内容可改变
声明:int * const p=&a;
注:指针常量必须在声明的同时对其初始化,不允许先声明一个指针常量随后再对其赋值,这和声明一般的常量是一样的
区分两者:*为界,左定值,右定向。const在*左边=指针指向的内容不可改变(常量指针),const在*右边=指针指向的位置不可改变(指针常量)
int a = 1; //定义变量 const int b = 2; //定义常量 const int *ptr1 = &a; //定义常量指针【并不能通过ptr1修改a的值,但a本身不是常量,a本身是可以修改的】 int* const ptr2 = &a; //定义指针常量,必须赋值 int *ptr3 = &b; //错误,不能把常量的地址赋给指针变量 const int* ptr4 = &b; //正确,可以把常量的地址赋给常量指针 *ptr1 = 3; //错误,间接引用常量指针不可以修改内存中的数据 *ptr2 = 4; //正确,间接引用指针常量可以修改内存中的数据 ptr1 = &b; //正确,常量指针可以指向其他变量 ptr2 = &b; //错误,指针常量不可以指向其他变量 const int * const ptr5 = &a; //常量指针常量,即不可以间接引用修改内存数据,也不可以指向别的变量 *ptr5 = 5; //错误,不可以间接引用修改内存数据 ptr5 = &b; //错误,不可以修改指向的对象
参考: