1、const是constant的缩写,是恒定不变的意思,也翻译为常量常数等,很不幸,正是因为这一点,很多人都认为被const修饰的是常量,这是不精确的,精确的说应该是只读的变量,其值在编译时不能被使用,因为编译器在编译时不知道其存储的内容。
const推出的初始目的,正是为了取代编译指令,消除他的缺点,同时集成他的优点,(define不是关键字哦!!)
const修饰的只读变量必须在定义的同时初始化。
case后面只能是常量或常量表达式,而不能是const修饰的只读变量。
const 修饰的只读变量不能用来作为定义数组的维数,
也不能放在case 关键字后面。
2、节省空间,避免不必要的内存分配,同时提高效率
编译器通常不为普通const只读变量分配内存空间,而是将它们保存在符号表中,这使得它成为一个编译期间的值,没有了存储与读内存的操作,使得它的效率也很高。
例如:
#define M 3; //宏常量
const int N=5; //此时并未将N放入内存中
………………
int i=N; //此时为N分配内存,以后不再分配!
int I=M; //预编译期间进行宏替换,分配内存
int j=N; //没有内存分配
int J=M //再进行宏替换,又一次分配内存。
const 定义的只读变量从汇编的角度来看,只是给出了对应的内存地址,而不是象#define
一样给出的是立即数,所以,const 定义的只读变量在程序运行过程中只有一份拷贝(因为
它是全局的只读变量,存放在静态区),而#define 定义的宏常量在内存中有若干个拷贝。
#define 宏是在预编译阶段进行替换,而const 修饰的只读变量是在编译的时候确定其值。
#define 宏没有类型,而const 修饰的只读变量具有特定的类型。
3、const修饰指针
const int *p; // p 可变,p 指向的对象不可变
int const *p; // p 可变,p 指向的对象不可变
int *const p; // p 不可变,p 指向的对象可变
const int *const p; //指针p 和p 指向的对象都不可变
先忽略类型名(编译器解析的时候也是忽略类型名),我们看const 离哪个近。“近水楼
台先得月”,离谁近就修饰谁。
const int *p; //const 修饰*p,p 是指针,*p 是指针指向的对象,不可变
int const *p; //const 修饰*p,p 是指针,*p 是指针指向的对象,不可变
int *const p; //const 修饰p ,p 不可变,p 指向的对象可变
const int *const p; //前一个const 修饰*p,后一个const 修饰p ,指针p 和p 指向的对象
都不可变
4、const修饰函数的参数
const 修饰符也可以修饰函数的参数,当不希望这个参数值被函数体内意外改变时使
用。例如:
void Fun(const int i);
告诉编译器i 在函数体中的不能改变,从而防止了使用者的一些无意的或错误的修改。
5、const修饰函数的返回值
const 修饰符也可以修饰函数的返回值,返回值不可被改变。例如:
const int Fun (void);
在另一连接文件中引用const 只读变量:
extern const int i; //正确的声明
extern const int j=10; //错误!只读变量的值不能改变。
一 const与指针
1 指针常量
int*const ptr;
指针常量,即不可以将ptr修改为指向内存中另一处的地址,但可以用它来改变它所指向的地址处的数据内容。
//const.cpp
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int temp = 4;
cout << temp << endl;
//ptr被const修饰 定义时必须初始化
int *const ptr = &temp;
*ptr = 5;
cout << temp << endl;
return 0;
}
程序运行截图:
2 常量指针
const int *ptr; (常量指针的另一种写法int const *ptr)
常量指针,即可以将ptr修改为指向内存中另一处的地址,但不可以用它来改变它所指向的地址处的数据内容。
//const.cpp
#include <iostream>
#include <cstring>
using namespace std;
int main()
{
int temp1 = 4;
int temp2 = 5;
const int *ptr;
ptr = &temp1;
cout << "*ptr:" << *ptr << endl;
ptr = &temp2;
cout << "*ptr:" << *ptr << endl;
return 0;
}
程序运行截图:
3 指向const常量的const指针
const int *const ptr; (另一种写法int const *const ptr)
指向const常量的const指针,即ptr所指向的内存地址和所指向的地址处的数据内容都不能被修改
PS:const离谁比较近,则谁的值不能被改变
二 const与函数
1 const修饰函数的参数
const使该参数在函数中不能被改变
void copy(char *strDes, const char *strsrc);
即strsrc指针所指向的值在copy函数中不能被改变,如果意外的改动该指针,编译器会报错
注意:
不用将“值传递”的方式(void copy(int x, in y))加const修饰,因为函数会自动产生临时变量用于复制该参数,参数本来就不需要保护。
2 const修饰函数的返回值
const int* add(int x, int y);
即add函数的返回值(即指针)的内容不能被修改,该返回值只能被赋值给加const修饰的同类型指针
const int *p = add(3, 5);
注意:
如果函数返回值是“值传递方式”(int add(int x, int y)),由于函数会把返回值复制到外部临时的存储单元中,加const修饰没有意义。
3 const成员函数
任何不会修改类的数据成员(即函数中的变量)的函数都应该声明为const类型。在编写const成员函数时,如果不小心修改了数据成员,或者调用了其他非const成员函数,编译器会报错,这种做法将大大提高程序的健壮性。
- //test.cpp
- class test
- {
- public:
- void set(int);
- //const成员函数
- int get()const;
- private:
- int value;
- };
- int test::get()const
- {
- //编译错误 修改数据成员value
- ++value;
- //编译错误 调用了非const函数
- set(5);
- return value;
- }