改编自
http://baike.sogou.com/v64494396.htm?fromTitle=CONST
http://blog.csdn.net/lihao21
http://blog.sina.com.cn/s/blog_79b01f6601018xdg.html
- const与#define宏定义的对比:
const可以节省空间,避免不必要的内存分配。(const是为了消除#define的缺点而产生的)
例如:
#define PI 3.14159 //常量宏
double I=PI; //编译期间进行宏替换,分配内存
double J=PI; //再进行宏替换,又一次分配内存!
const double Pi=3.14159; //此时并未将Pi放入RAM中
double i=Pi; //此时为Pi分配内存,以后不再分配!
double j=Pi; //没有内存分配
const定义常量从汇编的角度来看,只是给出了对应的内存地址,而不是像#define一样给出的是立即数,所以,const定义的常量在程序运行过程中只有一份拷贝,而#define定义的常量在内存中有若干份拷贝。
- const常用用法:左定值,右定向
1)const在前面
const int nValue; //nValue是const
const char *pContent; //*pContent是const, pContent可变
const char* const pContent; //pContent和*pContent都是const
2)const在后面,与上面的声明对等
int const nValue; //nValue是const
char const * pContent; //*pContent是const, pContent可变
char* const pContent; //pContent是const,*pContent可变
char const* const pContent; //pContent和*pContent都是const
const只修饰其后的变量,至于const放在类型前还是类型后并没有区别。如:const int a和int const a都是修饰a为const。
3)指针指向的变量的值不能变,指向可变(左定值)
int x = 1;
int y = 2;
const int* px = &x;
int const* px = &x; //这两句表达式一样效果
px = &y; //正确,允许改变指向
*px = 3; //错误,不允许改变指针指向的变量的值
4)指针指向的变量的值可以改变,指向不可变(右定向)
int x = 1;
int y = 2;
int* const px = &x;
px = &y; //错误,不允许改变指针指向
*px = 3; //正确,允许改变指针指向的变量的值
5)指针指向的变量的值不可变,指向不可变
int x = 1;
int y = 2;
const int* const px = &x;
int const* const px = &x;
px = &y; //错误,不允许改变指针指向
*px = 3; //错误,不允许改变指针指向的变量的值
6)
typedef char * pStr;
char string = "bbc";
const char *p1 =" string"; //1式
const pStr p2 =" string"; //2式
p1++;
p2++;
答案:const使用的基本形式: const type m;限定m不可变。替换基本形式中的m为1式中的*p1,替换后const char *p1;限定*p1不可变,当然p1是可变的,因此问题中p1++是对的。替换基本形式中的type为2式中的pStr,替换后const pStr m;限定m不可变,题中的pStr就是一种新类型,因此问题中p2不可 变,p2++是错误的。
7)在c中,对于const定义的指针,不赋初值编译不报错,
int* const px;这种定义是不允许的。(指针常量定义的时候对其进行初始化,右定向,必须指定指针指向)
int const *px;这种定义是允许的。(常指针可以再定义的时候不初始化,左定值,可以不赋初值)
- const成员函数: 若将成员成员函数声明为const,则该函数不允许修改类的数据成员。
在C++中,只有被声明为const的成员函数才能被一个const类对象调用。
const Screen blankScreen;
blankScreen.display(); // 对象的读操作
blankScreen.set(‘*’); // 错误:const类对象不允许修改
1)值得注意的是,把一个成员函数声明为const可以保证这个成员函数不修改数据成员,但是,如果据成员是指针,则const成员函数可以修改指针指向的对象。
2)const成员函数可以访问非const对象的非const数据成员、const数据成员,也可以访问const对象内的所有数据成员;
3)非const成员函数可以访问非const对象的非const数据成员、const数据成员,但不可以访问const对象的任意数据成员;
4)作为一种良好的编程风格,在声明一个成员函数时,若该成员函数并不对数据成员进行修改操作,应尽可能将该成员函数声明为const 成员函数。
- 在const成员函数中,用mutable修饰成员变量名后,就可以修改类的成员变量了。
- 类中的常量:有时我们希望某些常量只在类中有效。由于#define定义的宏常量是全局的,不能达到目的,于是想当然地觉得应该用const修饰数据成员来实现。const数据成员的确是存在的,但其含义却不是我们所期望的。const数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的,因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。
不能在类声明中初始化const数据成员。以下用法是错误的,因为类的对象未被创建时,编译器不知道SIZE的值是什么。
class A
{…
const int SIZE = 100; // 错误,企图在类声明中初始化const数据成员
int array[SIZE]; // 错误,未知的SIZE
};
const数据成员的初始化只能在类构造函数的初始化表中进行,例如
class A
{…
A(int size); // 构造函数
const int SIZE ;
};
A::A(int size) : SIZE(size) // 构造函数的初始化表
{
…
}
A a(100); // 对象 a 的SIZE值为100
A b(200); // 对象 b 的SIZE值为200
怎样才能建立在整个类中都恒定的常量呢?别指望const数据成员了,应该用类中的枚举常量来实现。例如
```
class A
{…
enum { SIZE1 = 100, SIZE2 = 200}; // 枚举常量
int array1[SIZE1];
int array2[SIZE2];
};
枚举常量不会占用对象的存储空间,它们在编译时被全部求值。枚举常量的缺点是:它的隐含数据类型是整数,其最大值有限,且不能表示浮点数(如PI=3.14159)。sizeof(A) = 1200;其中枚举部长空间。
```enum EM { SIZE1 = 100, SIZE2 = 200}; // 枚举常量 sizeof(EM) = 4;```