Chinaunix首页 | 论坛 | 博客
  • 博客访问: 176382
  • 博文数量: 65
  • 博客积分: 1790
  • 博客等级: 上尉
  • 技术积分: 460
  • 用 户 组: 普通用户
  • 注册时间: 2010-09-21 23:51
文章分类
文章存档

2012年(8)

2011年(38)

2010年(19)

分类: C/C++

2011-02-24 23:47:22

const最初动机是取代预处理器#defines进行值替代。

1,值替代

为所有的内部数据类型以及由它们所定义的变量使用限定符const

2,头文件里的const

const默认为内部连接。当定义一个常量时,必须赋一个值给它。C++编译器通常并不为const分配存储空间,相反它把这个定义保存在符号表里,当const被使用时,在编译器会进行常量折叠。

3,const的安全性

const int i=100;//typical constant

long address = (long)&i;//forces storage

**迫使编译器给i分配存储空间

4,集合

编译器不能把一个集合存放在它的符号表里,所以必须分配内存。

const int i[]={1,2,3,4};

float f[i[3]];//error C2057: 应输入常量表达式

**i[3]在编译时不能被使用,编译器在编译期不需要知道存储的内容。

5,与C语言的区别

C规范包含const,意思是“一个不能改变的普通变量”。总是占用存储而且它的名字是全局符。C编译器不能把const看成一个编译期间的常量。

const bufsize=100;

char buf[bufsize];//bufsize占用存储,C编译器不知道在编译期的值。

C语言可以这样写:

const bufsize;//C++中编译错

extern const bufsize;//declaration only,C++中未指定值时只能声明const变量

6,指针

处理const指针时,编译器努力阻止存储分配并进行常量折叠。

const int* x;//指针x,指向一个const int。这里不需要初始化,因为x可以指向任何东西,即x不是一个const

int const* x;//意义同上

int d=1;

int* const x=&d;//x是一个指针,指向int的const指针。const变量,编译器要求给它一个初始化值。这个值在指针生命期不变。

int * u=&w, v=0;//定义一个int* u和一个非指针int v

7,

int d=1;

const int e=2;

int* v=&e;//illegal,e const

int* v=(int*)&e;//legal but bad practice

C++有助于防止错误发生,但如果程序员自己打破这种安全机制,它也无能为力。

8,const没被调用的地方是串字面值

char* cp="howdy";

编译器接受它而不报告错误,从技术上讲,这是一个错误。

char* cp="howdy";
*cp=(const char)"new str";//0x00411a7d 处最可能的异常: 0xC0000005: 写入位置 0x00417880 时发生访问冲突

串字面值实际上是常量串,然而编译器把它们作为非常量看待,因为有许多现有的C代码是这样做的。

9,函数参数

如果以值传递对象时,对用户来说,用const限定没有意义(const意味着传递的参数在函数里不能被修改)。以const返回值或地址,意味着值或地址内容不会被改变。

void f1(const int i){

  i++;/illegal --compile time error

}

为了不是调用者混淆,在函数内部用const限定参数优于在参数表里用const限定参数。

void f2(int ic){

  const int& i=ic;

  i++;//illegal compile time error

}

这时对象的常量性不是函数特性标志的部分,仅对函数实现由意义,所以它对用户来说是不可见的。

10,返回const值

const int g();

:::返回这个变量的值,因为这个变量被制作副本,所以初值不会被修改。这时const看起来没有什么意义。

int f3(){return 1;}

const int f4(){return 1;}

int main(){

  const int j=f3();//works fine

  int k=f4();//but this work fine too

}

:::对于内部数据类型,返回值是否是常量并没有关系,所以返回内部数据类型,最好去掉const避免用户程序员混淆。返回内部数据类型值时,const没有意义原因是:编译器已经不让它成为一个左值,因为它总是一个值而不是一个变量。

处理用户定义类型时,返回值为常量是很重要的,如果返回一个常量类对象,则它不能是一个左值。

11,临时变量

有时在求表达式值期间,编译器必须建立临时对象。编译器负责决定它们的去留以及它们存在细节。它们自动成为常量。

12,传递和返回地址

无论什么时候传递一个地址给函数,都应有尽可能用const修饰。是否选择返回一个指向const的指针,取决于我们想让用户用它干什么。

const int* const w(){

  static int i;

  return &i;

}

int* ip2=w();//Not ok 编译器拒绝把函数w()的返回值赋给一个非const指针,ip2指向的值可以被改变

const int* const ccip=w();//ok 指针ccip指向的值不可改变,指针不可改变

const int* cip2=w();//ok 指针cip2指向的值不可改变,w()返回的值被拷贝赋值给cip2

13,标准参数传递

通过const引用传递参数,函数将不改变该地址所指的内容,从用户程序员的观点,效果恰好与值传递一样。

class X{};

X f(){return X();}//return by value

void g1(X&){}//pass by non-const reference

void g2(const X&){}/pass by const reference

g1(f1());//Error:const temporary created by f()

g2(f1());//g2 take a const reference

:::一个总是常量的临时变量,它地址可以传递给一个函数,临时变量通过引用传递给一个函数时,这个函数参数一定是const引用。

14,类里的const

目的:在一个类里建立一个局部常量,用户常数表达式,在编译期被求值。const无法满足,只能用enum完成。

类对象里const分配存储并代表一个值,这个值一旦被初始化就不能改变。类里使用const意思是:这个对象生命期内,这是一个常量。然而对不同的对象可以含一个不同的值。

在一个类里建立一个const时,不能给它初值。在构造函数主体里,必须初始化。但无法防止在构造函数主体的不同地方改变const的值。

构造函数初始化表达式

初始化表的初始化发生在构造函数的任何代码执行之前。

fred::fred():size(100){}

内部数据类型构造函数

把内部数据类型的构造函数(仅指赋值)扩展为一般情形,可以写:float pi(3.1415);

15,编译期间类里的常量

在类对象里进行存储空间分配,编译器不能知道const的内容是什么,所以不能把它用作编译期间常量。

class bob{

  const int size=100;//error C2864: “X::size”: 只有静态常量整型数据成员才可以在类中初始化

  int array[size];//illegal

  enum { size=1000};//使用一个不带实例的无标记的enum,枚举的所有值必须在编译期建立。

  int i[size];

:::使用enum不会占用对象的存储空间,枚举常量在编译期被全部求值。

static const也可以在类里定义静态常量

16,const对象和成员函数

仅仅声明一个函数在类定义里是const的,不能保证成员函数也如此定义,所以编译器迫使程序员在定义函数时要重申const说明。

const放在函数声明前意味着返回值是常量,这不合语法。必须把const标识符放在参数表后。

关键字const必须同样的方式重复出现在定义里,否则编译器把它看成一个不同的函数。

任何不修改成员数据的函数应该声明为const函数,这样它可以由const对象使用。

17,按位和按成员const

按位const意思是对象中的每个位是固定的,所以对象的每个位映像从不改变。按成员const意思是,虽然对象从概念上讲是不变的,但是某个成员可能有变化。const成员函数里改变数据成员的两种方法:

a,强制转换const,取this(这是当前对象的const指针)强制转换成指向当前对象的普通指针。

class Y{

  int i,j;

public:

  Y(){i=j=0;}

  void f() const;

};

void Y::f() const{

  i++;//Error --const number function

  ((Y*)this)->j++;//ok: cast away const-ness this是const指针,转换成普通指针

}

main(){

  const Y yy;

  yy.f();//实际修改了对象Y的成员

}

b,使用关键字mutable,指定一个特定数据成员可以在一个const对象里改变

class Y{

  int i;

  mutable int j;

public:

  Y(){i=j=0;}

  void f() const;

};

void Y::f() const{

  i++;/error --const member function

  j++;//ok mutable

}

18,可变的volatile

语法与const一样,volatile意思是“在编译器认识的范围内,这个数据可以被改变”。

const volatile对象,这个对象不能被程序员改变,但可通过外面的工具改变。

就像const一样,可以对数据成员、成员函数和对象本身使用volatile,可以并且也只能为volatile对象调用volatile成员函数。

关键字const能将对象、函数参数、返回值及成员函数定义为常量,并能消除预处理器defines的值替代。

 其它关于const的文章:

1,C++面试之const、#define http://blog.csdn.net/crescent_star/archive/2009/03/18/4001602.aspx

阅读(1674) | 评论(0) | 转发(0) |
0

上一篇:C++输入输出流

下一篇:C++内联函数

给主人留下些什么吧!~~