C++ 基础内容, 不值一提 Author:Jacky Wu 2006-4-17 引用该文章,必须注明其出处 http://blog.youkuaiyun.com/imwkj
一:常量 const 1:define 与 const define用预处理器只能做源代码的文本替代,不能做类型检查,这给程序带来不稳定因素 #define ARRAY_SIZE 100 在预处理过程中,仅仅用值 100 替代在代码中出现的 ARRAY_SIZE,虽然我们在#define 的时候,已经设想它应该是个int型常量,但是,ARRAY_SIZE 并没有任何类型信息。 而用const 可以解决这个问题 const int ARRAY_SIZE = 100; 在此语句中,定义了一个整数型常量,在其作用域内,它是一个恒定不变的常量(这显然很好理解),对于所有内部类型,甚至包括自定义类的对象,都可以使用const 限定符将之表示为一个常量。而这个常量是有类型信息的,在赋值或者参数传递时,会做类型检查,这带来了额外的安全性。 因此,就仅凭这一点,在C++中就应当多用const 而少用 #define 来设置一个常量。
2:const 与 数组 当编译器遇到const 定义时,会根据语句的复杂性来决定是否分配空间给此常量,这有两种情况: (1) 用extern 来制定该常量为外部连接,或者取const 常量的地址,或者将它作为引用参数传递给函数,这会引起编译器分配内存给该常量 (2) 用const 限定的简单常量,或者在运行期间通过计算获得的常量,编译器将会将它保存在符号表里,不会分配空间给该常量。 对于此特性,并不需要清楚的知道编译器的行为,在程序中,仅需要知道,两点: (1) 常量在定义的时候是必须赋值的,通过编译时间直接给定或者在编译时间通过计算得到都可以 (2) const 限定的常量在其运行的生命期内是不可以改变的(不可以改变在定义时的初值) 对此,可以通过考察下面的程序来理解这两个特性:
上面指出了在定义数组时const 显示出的一些特性,但是在用 const限定数组时,又会怎样呢。 在用const限定数组时,仅仅代表“此数组内容是不可以改变的” ,对于数组保存的值,编译期间是无法获得的。看如下代码。
3:const 与指针 const 与指针之间的关系包括两方面:const 修饰指针指向的对象(此时表示对象时常量), 和const 修饰指针的地址(此时表示,指针的地址值是常量,该地址不可以作为左值进行运算)。 (1) 指向const对象的指针 定义方式: const int *ptr; 或者 int const* ptr; 都表示ptr为普通指针,但是ptr所指向的对象是不可以改变的,也就是说,*ptr不可以用作左值操作。 看下面的语句: const int x = 100; int m = 200; const int* ptr; //不需要赋处值
ptr = &m; //这是可以的,这仅仅代表*ptr 不可以改变 //*ptr = 300; //错误,不可以改变*ptr 内容
ptr = & x; //*ptr = 200; //错误,不可以改变*ptr 内容
(2) 指针的地址是不可以改变的 int m[5] = {1, 2, 3, 4, 5}; int* const ptr = m; //ptr不可以改变,定义时必须赋值,但是*ptr时可以改变的。 *ptr = 200; //运行后,m [0]= 200; // ptr++; //错误,ptr不可以改变,它仅能表示期定义时的地址。
(3) 把一个const 指针指向一个const 对象。 int m = 100; const int* const ptr = &m; //或者 int const* const ptr = &m 两个语句代表一个意思。 显然,*ptr 和ptr 都不可以做左值。 const 限定指针的关系基本就这三个类型,在阅读时你这样理解:在头脑里画一条垂直线穿过指针声明中的星号(*)位置,如果const出现在线的左边,指针指向的数据为常量;如果const出现在线的右边,指针本身为常量;如果const在线的两边都出现,二者都是常量(Effective C++)。 这有几点是要注意的: (1) 可以将一个非const 对象的地址 赋给一个const 指针,例如下面的语句是可以的: int m = 200; const int* ptr; //不需要赋处值 ptr = &m; //这是可以的,这仅仅代表*ptr 不可以改变 //*ptr = 300; //错误,不可以改变*ptr 内容 不能把一个const 对象的制止赋给非const 指针,但是可以通过强制类型转换做到这一点(不推荐): const int m = 200; //int* ptr = &m; //非法操作,不可以 int* ptr2 = (int*)&m; //合法操作,但是最好不用。 *ptr2 = 300; //合法操作,但完全破坏了常量的安全性检查!! //运行后,*ptr 2 = 300, m=200, //而 *(int*)&m = 300; 不可理解.这里说明 //(int*)&m 和 &m 是不相等的两个地址!!!
4:const 与函数参数,返回值 (1) const 传递值 例如 void fun( const int i) { //这里仅代表i 在fun内时不可以变化的 } 为达到这样的效果,最好这样做: void fun( int ip) { const int& i= ip; //常量引用,异曲同工,效果更好 } (2)返回const 值 对于内部类型(int, char,等)来说,返回const 值没有太多意义,但是对于用户自定义类型来说,用const限定返回值就保证了函数返回值不能用作左值操作。例如:
(3)const 限定传递或返回地址和引用
对于参数传递,用const 限定指针或者引用传递,可以阻止在函数中修改原来对象的内容。而通过const 限定的引用传递也可以接收临时对象作为参数。
5:const 与类 (1)const 数据成员 对于类中的const 数据成员指的是“该类生成的对象生命期内,该成员是不可变的”,在对象生成之前必须已经赋值。对于const数据成员,唯一可以赋值的地方是“构造函数初始化列表 constructor initializer list),对于const数据成员使用方法如下:
但是,这样的操作并不能获得和#define 相近的编译期间常量,如果想获得这样的编译期间常量,我们有两中方法: (a) 使用static const
在定义一个static const 常量的时候必须对其初始化,如下: (b)使用 “enum hack” 使用枚举成员的特点,它在编译期间必须有值,因此,这恰恰获得了编译期间常量的效果,如下:
(2)const 对象和 const 成员函数 对于const对象和const成员函数之间的关系可以这样理解:const 对象只可以调用由const 限定的类的成员函数,而const限定的成员函数不能修改类中的普通的数据成员(通过指针可以修改,但是会出现不必要的麻烦,除非必须,否则不要这样做)。 与const 对象和const成员函数相关的还有两个关键字,mutable(易变的),volatile(不稳定的,可变的)
对于volatile 关键字主要作用是提示编译器该对象的值可能在编译器未监测到的情况下被改变,因此编译器不能武断地对引用这些对象的代码作优化处理。在一般情况下,volatile变量不由用户改变,由系统驻留程序改变。对于此,就不多说明了。
|