在《Effective c++》中,条款02指出:尽可能的使用const替换define;条款03指出:尽可能的使用const。可见,define在C++中不太受欢迎。本文将总结const的一般用法,并说明其和define两者的区别。
1、const的一般用法与特点
(1)将常见的数据类型约束为“不可被改动的对象”。
例如一下语句:cont int a=5;
将整型变量a声明为常量,即“只读”。
(2)提高运行效率
在上述语句开始编译时,编译器通常并不为变量a分配存储空间,而是将其保存在符号表中,这使得它在编译期间成为一个常量,少了存储与读内存的操作,提高运行效率。
(3)节省内存
在程序运行期间,只进行一次拷贝,并且在静态存储区中为const变量分配内存。比如,执行下面的语句:
const int a=5;
int b=a; //在静态存储区分配内存
int c=a; //不再进行内存分配
(4)const修饰指针
已知const int a1=3;
一般有四种情形:
1. const int *a=&a1;
//a是一个指向常整型数的指针,即指针可变,而数据不可变
2. int *const a=&a1;
//a是一个指向整型数的常指针,即指针不可变,数据可变
3. const int *const a=&a1;
//a是一个指向常整形数的常指针,即指针不可变,并且数据不可变
4. 另外const int
等价于int const
。
看完有点晕~。下面利用代码解释上面的种种神操作~~~
#include<iostream>
using namespace std;
int main()
{
int temp[]={3,4,5}; //声明整型数组,数组名为数组的首地址
const int *a=&temp; //根据上面的解释,a为指向常整形数的指针,即a指向的整型数不可修改,但指针a可修改
cout<<"a指向的地址为: "<<a<<endl; //运行后,输出“012FF9D4”
cout<<"a指向的整型数为: "<<*a<<endl; //运行后,输出3,即数组首元素
a++; //修改指针a,使其指向下一个地址
//*a=*a+1; //修改a指向的整型数。报错,*a为常量,不可修改。符合预期
cout<<"a指向的地址为: "<<a<<endl; //运行后,输出“012FF9D8”,指向下一个地址,即“012FF9D4”+4个字节
int *const b=temp; //根据上面的解释,b为指向整型数的常指针,即指针b不可修改,但指针b指向的整型数可修改
cout<<"b指向的地址为: "<<b<<endl; //运行后,输出“012FF9D4”
cout<<"b指向的整型数为: "<<*b<<endl; //运行后,输出3,即数组首元素
//b++; //报错,指针b不可修改
*b=*b+1; //修改指针b指向的整型数
cout<<"b指向的整型数为: "<<*b<<endl; //运行后,输出4,即3+1=4。符合预期
const int *const c=temp; //指向常整形数的常指针
cout<<"c指向的地址为: "<<c<<endl; //运行后,输出“012FF9D4”
cout<<"c指向的整型数为: "<<*c<<endl; //运行后,输出3,即数组首元素
//c++; //报错,指针b不可修改
//*c=*c+1; //报错,指针b指向的整型数不可修改。符合预期
}
(5)修饰类的成员变量
利用const修饰类的成员变量时,const成员变量只在某个对象的生存期内是“只读”的,而C++可以为一个类同时声明许多对象,从而各个对象的同一个const成员变量值有可能不相同。这就相当于const成员变量为每个对象单独拥有。
由此,可以得出,const类型的成员变量不能在类中定义。
那么,怎么来声明和定义一个const类型的成员变量呢?一般有两种方式:
- 在类中声明为”const static”类型,在类外利用“const <变量类型> <类名>::<变量名> =<值>”定义;
- 在类中声明为”const”类型,在构造函数的初始化列表中定义。
看下面的代码:
#include<iostream>
using namespace std;
class const_test{
const int a; //在类内声明常整型成员变量a,默认为private
const static int b; //在类中利用“const static”声明静态常整型成员变量b
public:
const_test(int x):a(x){} //在构造函数的初始化列表中初始化常整型变量x
~const_test(){}
};
const int const_test::b=4; //在类外定义
(6)其他情况
除上面的情形外,const也可以用于下列情形:
1. const也可以声明定义全局变量,并可以在多个文件中使用:
在主文件中,要同时声明并定义,如const int a=3;
;在其他文件中使用时,通过extern const int a;
实现。
2. const可以修饰类的成员函数,但函数中不能访问非const成员函数,并且不能修改任何成员变量(mutable类型除外);
3. const可以修饰引用,此时引用“只可读”
4. const可以修饰普通函数,函数返回值,函数形参,保持“可读属性”。
2、const比define的优势
主要有以下几方面的区别:
- const修饰,编译时进行类型检查,而利用define时,不进行类型检查(因为没有类型……)
- 利用const时,只进行一次拷贝,节省内存,而define类似于替换,每次都得调用并分配内存;
- 在编译时,通常编译器并不为const修饰的变量分配内存,而放入符号表中,使得其在编译期间成为一个常量,提高效率,而define在预处理阶段就进行替换;
- define定义的变量只能作用于单个文件,而const修饰的变量可以跨文件使用;
- define只是简单的复制,不进行运算符的运算,如下面的经典例子:
#include<iostream>
using namespace std;
#define a x+y
int main()
{
int x=1,y=2;
cout<<a*a<<endl; //输出5,因为1+2*1+2=5
}