C++ const引用详解

C++ const引用详解

转自:http://chio.cnblogs.com/


(1)在实际的程序中,引用主要被用做函数的形式参数--通常将类对象传递给一个函数.引用必须初始化. 但是用对象的地址初始化引用是错误的,我们可以定义一个指针引用。

1 int ival = 1092;
2 int &re = ival;   //ok
3 int &re2 = &ival;   //错误
4 int *pi = &ival;
5 int *&pi2 = pi;   //ok

(2)一旦引用已经定义,它就不能再指向其他的对象.这就是为什么它要被初始化的原因。

(3)const引用可以用不同类型的对象初始化(只要能从一种类型转换到另一种类型即可),也可以是不可寻址的值,如文字常量。例如:

double dval = 3.14159;
//下3行仅对const引用才是合法的
const int &ir = 1024;
const int &ir2 = dval;
const double &dr = dval + 1.0;

上面,同样的初始化对于非const引用是不合法的,将导致编译错误。原因有些微妙,需要适当做些解释。

引用在内部存放的是一个对象的地址,它是该对象的别名。对于不可寻址的值,如文字常量,以及不同类型的对象,编译器为了实现引用,必须生成一个临时对象,将该对象的值置入临时对象中,引用实际上指向该对象(对该引用的操作就是对该临时对象的操作),但用户不能访问它。

例如:

double dval = 23;
const int &ri = dval;

编译器将其转换为:

int tmp = dval; // double -> int
const int &ri = tmp;

同理:上面代码

double dval = 3.14159;
//下3行仅对const引用才是合法的
const int &ir = 1024;
const int &ir2 = dval;
const double &dr = dval + 1.0;

内部转化为:

double dval = 3.14159;
//不可寻址,文字常量
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;  //正确

(5)对于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

(6)const引用的语义到底是什么?

const引用表示,试图通过此引用去(间接)改变其引用的对象的值时,编译器会报错!我们仍然可以直接改变其指向对象的值,只是不能通过引用改变。总结来说就是const引用只是表明:保证不会通过此引用间接的改变被引用的对象!下面是一个简单的例子:

 1 #include <iostream>
 2 using namespace std;
 3
 4 int main()
 5 {
 6     int val = 1024;
 7     const int &ir = val;
 8     
 9     val++;//我们仍然可以通过val直接改变其值
10     //ir++;//通过ir来改变val的值,编译时会出错
11
12     cout << val << " " << ir << endl;
13
14     return 0;
15 }

另外,const既可以放到类型前又可以放到类型后面,放类型后比较容易理解:

string const *t1;
const string *t1;
typedef string* pstring;
string s;
const pstring cstr1 = &s;//此时放前面就出错了
pstring const cstr2 = &s;//但是放在类型后面不会出错

(7)补充:const引用与非const引用的对比http://my.oschina.net/sasa/blog/7921

1、const引用可读不可改,与绑定对象是否为const无关;非const引用可读可改,只可与非const对象绑定

例如:

const int ival = 1024;
const int &refVal = ival; // ok: both reference and object are const
int &ref2 = ival;            // error: nonconst reference to a const object

2、非const引用只能绑定到与该引用同类型的对象,const引用则可以绑定到不同但相关的类型的对象或绑定到左值,同时const引用可以初始化为不同类型的对象或者初始化为右值,如字面值常量。例如:

int i = 42;
// legal for const references only
const int &r = 42;//初始化为右值
const int &r2 = r + i;//同样的初始化对于非const引用却是不合法的,而且会导致编译时错误。
double dval = 3.14;
const int &ri = dval;//不同类型对象

编译器会把这些代码转换成如以下形式的编码:

int temp = dval;          // create temporary int from the double
const int &ri = temp;   // bind ri to that temporary

3.const引用和非const引用在内存中的对比

例如const引用:

const int t = 9;
const int& k = t;
cout<<&k<<endl;
cout<<&t<<endl;
输出是
0012FF6C
0012FF74


例如非const引用:

int t = 9;
int& k = t;
cout<<&k<<endl;
cout<<&t<<endl;
输出是
0012FF74
0012FF74


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值