const限定符的使用

1、定义const对象

const int bufSize = 512; // input buffer size

定义 bufSize 为常量并初始化为 512。变量 bufSize 仍然是一个左值但是现在这个左值是不可修改的。

任何修改 bufSize 的尝试都会导致编译错误:

bufSize = 0; // error: attempt to write to const object

因为常量在定义后就不能被修改,所以定义时必须初始化:

const std::string hi = "hello!"; // ok: initialized

const int i, j = 0; // error: i is uninitialized const 


2、const对象默认为文件的局部变量

与其他变量不同,除非特别说明,在全局作用域声明的 const 变量是定义该对象的文件的局部变量。此变量只存在于那个文件中,不能被其他文件访问。

通过指定 const 变更为 extern,就可以在整个程序中访问 const 对象:

// file_1.cpp

// defines and initializes a const that is accessible to other files

extern const int bufSize = fcn();


// file_2.cpp

extern const int bufSize; // uses bufSize from file_1

// uses bufSize defined in file_1

for (int index = 0; index != bufSize; ++index)

// ...


3、const引用

const 引用是指向 const 对象的引用:

const int ival = 1024;

const int &refVal = ival;// 合法

int &ref2 = ival;// 不合法

可以读取但不能修改 refVal ,因此,任何对 refVal 的赋值都是不合法的。这个限制有其意义:不能直接对 ival 赋值,因此不能通过使用 refVal 来修改ival。

同理,用 ival 初始化 ref2 也是不合法的:ref2 是普通的非 const 引用,因此可以用来修改 ref2 指向的对象的值。通过 ref2 对 ival 赋值会导致修改const 对象的值。

为阻止这样的修改,需要规定将普通的引用绑定到 const 对象是不合法的。

const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

int i = 42;

const int &r = 42;

const int &r2 = r + i;


double dval = 3.14;

const int &ri = dval;

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

int temp = dval;

const int &ri = temp;

注意:如果 ri 不是 const,那么可以给 ri 赋一新值。这样做不会修改 dval,而是修改了 temp。期望对 ri 的赋值会修改 dval 的程序员会发现 dval 并没有被修改。


4、指针与const限定符

1)指向const对象的指针

例:const  double *cpstr;

这cpstr是一个指向double类型的const对象,const限定的是cpstr指针所指的对象类型,而不是cpstr本身,也就是说,cpstr可以改变,但不能修改cpstr所指对象的值(即*cpstr=42 这个行为是错误的)。

把一个 const 对象的地址赋给一个普通的、非 const 对象的指针也会导致编译时的错误:

const double pi = 3.14;

double *ptr = π // error: ptr is a plain pointer

const double *cptr = π // ok: cptr is a pointer to const

不能使用 void* 指针保存 const 对象的地址,而必须使用 const void* 类型的指针保存 const 对象的地址:

const int universe = 42;

const void *cpv = &universe; // ok: cpv is const

void *pv = &universe; // error: universe is const

允许把非 const 对象的地址赋给指向 const 对象的指针,例如:

double dval = 3.14; // dval is a double; its value can be changed

const double *cptr = &dval; // ok: but can't change dval through cptr

在实际的程序中,指向 const 的指针常用作函数的形参。将形参定义为指向 const 的指针,以此确保传递给函数的实际对象在函数中不因为形参而被修改。


2) const指针

int errNumb = 0;

int *const curErr = &errNumb; // curErr is a constant pointer

我们可以从右向左把上述定义语句读作“curErr 是指向 int 型对象的const 指针”。与其他 const 量一样,const 指针的值不能修改,这就意味着不能使 curErr 指向其他对象。任何企图给 const 指针赋值的行为(即使给curErr 赋回同样的值)都会导致编译时的错误:

curErr = curErr; // error: curErr is const

与任何 const 量一样,const 指针也必须在定义时初始化。

指针本身是 const 的事实并没有说明是否能使用该指针修改它所指向对象的值。指针所指对象的值能否修改完全取决于该对象的类型。

例如,curErr 指向一个普通的非常量 int 型对象 errNumb,则可使用 curErr 修改该对象的值:

if (*curErr) {

errorHandler();
*curErr = 0; // ok: reset value of the object to which curErris bound

}


3)指向const对象的const指针

const double pi = 3.14159;

const double *const pi_ptr = π

本例中,既不能修改 pi_ptr 所指向对象的值,也不允许修改该指针的指向(即 pi_ptr 中存放的地址值)。可从右向左阅读上述声明语句:“pi_ptr 首先是一个 const 指针,指向(即 pi_ptr 中存放的地址值)。可从右向左阅读上述声明语句:“pi_ptr 首先是一个 const 指针,指向 double 类型的 const 对象”


4)指针和typedef

在 typedef中使用指针往往会带来意外的结果。下面是一个几乎所有人刚开始时都会答错的问题。假设给出以下语句:

typedef string *pstring;

const pstring cstr;

请问 cstr 变量是什么类型?简单的回答是 const pstring 类型的指针。

进一步问:const pstring 指针所表示的真实类型是什么?很多人都认为真正的类型是:

const string *cstr; // wrong interpretation of const pstring cstr

也就是说,const pstring 是一种指针,指向 string 类型的 const 对象,但这是错误的。

错误的原因在于将 typedef 当做文本扩展了。声明 const pstring 时,const 修饰的是 pstring 的类型,这是一个指针。

因此,该声明语句应该是把cstr 定义为指向 string 类型对象的 const 指针,这个定义等价于:

string *const cstr; // equivalent to const pstring cstr


5、const放在函数前与函数后的区别

1)放到函数前面修饰返回值的const,如const   a   fun2(   );   const   a*   fun3(   );   

  这样声明了返回值后,const按照"修饰原则"进行修饰,起到相应的保护作用。const   rational   operator*(const   rational&   lhs,   const   rational&   rhs)   
  {   
  return   rational(lhs.numerator()   *   rhs.numerator(),   
  lhs.denominator()   *   rhs.denominator());   
  }   
    
  返回值用const修饰可以防止允许这样的操作发生:rational   a,b;   
  radional   c;   
  (a*b)   =   c;   
    
  一般用const修饰返回值为对象本身的情况多用于二目操作符重载函数并产生新对象的时候。   
  [总结]   一般情况下,函数的返回值为某个对象时,如果将其声明为const时,多用于操作符的重载。通常,不建议用const修饰函数的返回值类型为某个对象或对某个对象引用的情况。   
  原因如下:   
  如果返回值为某个对象为const或某个对象的引用为const   ,则返回值具有const属性,则返回实例只能访问类a中的公有数据成员和const成员函数,并且不允许对其进行赋值操作,这在一般情况下很少用到。   
    
  [思考3]:   这样定义赋值操作符重载函数可以吗?   
  const   a&   operator=(const   a&   a);   
    
 2) 放在函数后,即类成员函数中const的使用

 一般放在函数体后,形如:void   fun()   const;   

如果一个成员函数的不会修改数据成员,那么最好将其声明为const,因为const成员函数中不允许对数据成员进行修改,如果修改,编译器将报错,这大大提高了程序的健壮性。   


以上是我根据《C++Primer》和一些网友的博客整理出来的,有错或补充或其它原因的希望大家指出和补充。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值