const修饰的值并不是常量,而是只读的变量。其值在编译时不能被使用,因为编译器在编译时不知道其存储的内容。
也就是其它 .cpp 文件看不到,所以用 extern 声明也没用
可将 const 变量的声明放在 .h 文件里,需要使用此常量的 .cpp 都 #include 它
编译器通常不为普通const只读变量分配存储空间,而是将它们保存在符号表中,这使得Tam它成为一个编译期间的值,没有了存储和读内存的操作,使它的效率很高。
#define M 3 //宏常量
const int N = 5; //此时未将N 放入内存
......
int i = N; //此时为N 分配内存,之后不再分配
int I = M; //预编译期间进行宏替换,分配内存
int j = N; //没有内存分配
int J = M; //再次进行宏替换,再次分配内存
const定义的只读变量从汇编角度上看,只是给出了对应的内存地址,而不是像 #define一样,给出的是立即数。所以,const定义的只读变量在程序运行过程中只有一份copy,因为他是全局的只读变量,放在静态区。#define 宏实在预编译阶段进行替换,const修饰的只读变量是在编译时确定其值。
下面的代码在存为C文件在VC6.0编译器下编译是错误的!为什么?
#include<stdio.h>
void main()
{
const int bufsize = 10 ;
char buf[bufsize] = {'a','b','c'};//error C2057:expected constant expression
//error C2466: cannot allocate an array of constant size 0
printf ("%S",buf);
}
在编译时,编译器并不知道const的值,它只是一个“运行时常量”。不是放在符号表里的。(编译原里的知识这里就不多讲了!)
然而把上面的代码改成CPP文件在VC6.0编译器下编译是通过的。
通常,C++编译器不为const创建存储空间,而是把它保存在“符号表”里,即“编译时常量”。默认情况下,C++中的const是内部连接的,也就是说,const仅在const被定义过
的文件里才是可见的。(因此,不用担心名字冲突)当定义一个const时,必须赋一个值给它,除非用extern做出了清楚的说明。当用extern说明了const时,编译器会强制为const
分配空间,而不是保存在符号表中。
const修饰的只读变量必须在定义的同时初始化。
用如下方法可以修改const常量,但是如果将const int i=0;放到main函数之外,作为全局变量,则施行的时候会报错。
#include<stdio.h>
main()
{
const int i=0;
int *p=&i;
*p=3;
printf("%d",i);
}
类中的常量:
在类中,const数据成员只在某个对象生存期内是常量,而对于整个类而言确实可变的,因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。
不能在类声明中初始化const数据成员,以下用法错误,因为类的对象还未被创建时,编译器不知道SIZE的值为多少:
class A
{
const int SIZE = 100;
int array[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
要建立在整个类中都恒定的常量,可用枚举常量来实现。但枚举常量是整数,不能表示浮点数
class A
{
enum {SIZE1 = 100,SIZE2 = 200};
int array1[SIZE1];
int array2[SIZE2];
}
------------------
用const提高函数健壮性
1、const修饰函数参数
如果参数作输出用,不管是什么数据类型,也不管是采用指针传递还是引用传递,都不能加const,否则该参数将失去输出功能。
如果参数作为输入:
值传递:形参变动不会影响实参,所以无需保护。不需要加const修饰。无需将void Func1(int x)写成void Func1(const int x),也无需将void Func2(A a)写成void Func2(const A a),A为用户自定义的数据类型。
引用传递:对于非内部数据类型的参数而言,像void Func2(A a)这样声明的函数效率较低,因为函数体内将产生A类型的临时对象用于复制参数a,而临时对象的构造、复制、析构过程都耗费时间。为了提高效率,可以将函数声明改为void Func2(A &a),引用传递不产生临时对象。但可能改变参数a,所以可以改为void Func2(const A &a) ,但内部数据类型就不需要如此修改,因为int等类型不存在构造析构的过程,值传递和引用传递的效率相当。
指针传递:加const修饰可以防止意外改动该指针。
void stringcopy(char * strdestination , const char strsource); //输出参数不可加const
用const修饰函数的返回值
如果给“指针传递”方式的函数返回值加const修饰,那么函数返回值的内容不可以被修改,而且只能被赋给加const修饰的同类型指针:
const char *getstring(void);
char *str = getstring();//错误
const char *str = getstring();//正确
如果函数返回采用“值传递”,由于函数会把返回值复制到外部临时存储单元,加const无作用:
不要把int getint(void)写成const int getint(void)
不要把A getA(void)写成const A getA (void)
-----------------------------------------------------
const修饰一般变量:
int const i = 2;或 const int i = 2;
修饰数组
int const a[5] = {1,2,3,4,5};
const int a[5] = {1,2,3,4,5};
修饰指针
const int *p;//p可变,p指向的对象不可变 常量指针
int const *p;//p可变,p指向的对象不可变 常量指针
int *const p;//p不可变,p指向的对象可变 指针常量
const int *const p;//指针p和p指向的对象都不可变。
修饰函数参数
修饰函数的返回值