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; //错误,不可以修改指向的对象

参考:

引用  常量指针

原文地址:https://www.cnblogs.com/beixiaobei/p/10446463.html