1.const修饰常量
功能与#define相同。
#define MAX 10;
const int MAX = 10;
但相比于使用#define定义的宏常量,const常量有数据类型,编译器会对其进行 数据类型检查,而宏常量只是简单的字符替换,编译器不会对其进行数据类型检查。
在另一个文件中引用const常量:
extern const int MAX; //正确,MAX在其他文件中已定义
extern const int MAX = 10;//错误,MAX在其他文件中已定义,不可再赋值。
2.const修饰变量
声明变量只读,不可被修改。
const int mm = 5;
注意:const变量定义时,必须初始化,并且以后不可被修改。
其实,上面的第1中情况,准确的讲,也应该属于第二种情况,这里分开来讨论主要是根据其与#define定义的宏常量等价来分的,因为第一种情况即const常量类似宏常量一般定义在头文件中的。
const与指针
指针常量:指针本身是常量,不可变。
int a;
int * const pt = &a; //pt是常量,定义时必须初始化
指向常量的指针:指针本身可变,指向的变量不可变。
const int * pt; //指针本身不是const的,不用初始化。
int const * pt; //与上一个等价。
注意:要区别是指针常量还是指向常量的指针,其实根据定义很好区别,如果const修饰的是*pt,则pt是指向常量的指针,const修饰的是pt,则pt是指针常量。
3.const修饰函数的参数
const不用于修饰输出参数,因为输出参数一般是要通过函数来改变的。
对于输入参数,如果输入参数采用”指针传递”,那么加const可防止意外地改变该指针,起到保护作用。
如:StrCopy(char * strDst, const char *strSrc);
strSrc是输入参数,strDst是输出参数,加上const后,函数体内如有语句修改strSrc值,编译器将报错。
如果输入参数,若采用”值传递”,因函数调用时,函数将自动用临时变量复制该参数,函数不会对该参数操作,所以加const也没用。
对于非内部数据类型的参数,如void Fun( A a)函数,在调用时,将产生A类型的临时变量复制a,而临时对象的创建将调用构造函数、拷贝构造函数、析构函数将消耗时间。为了提高效率,可以将函数改为void Fun( A &a),因为”引用传递”仅借用参数的别名,不用产生临时对象。但”引用传递”可能改变参数a的值,这可能不是我们期望的,所以可以改成这样void Fun(const A &a).
那对于void Fun(int b)是否有必要像上面一样改呢?,其实完全没有必要,因为对于内部数据类型,根本不存在构造函数和析构函数。
因此我们可以总结如下:
4.类中的const
4.1 const数据成员
const数据成员只在某个对象生存期内是常量,而对整个类而言是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。
不能在类的声明中初始化const数据成员,只能在构造函数的初始化表中进行。
如下两种方式均是错误的:(1)
class A
{
public:
const int con = 10; //错误,类声明时初始化。
};
(2)
class A
{
public:
A(int c);
const int con;
};
A::A(int c)
{
con = c;
}
正确的方式应该如下:
class A
{
public:
A(int c);
const int con;
};
A::A(int c):con(c)
{
}
void main(void)
{
const A(4);
}
既然const数据成员对整个类而言是可变的,那怎样建立在整个类中都是恒定的常量呢?我们可以采用枚举常量来实现。
class A
{
public:
enum{SIZE1 = 10,SIZE2 = 20}; //枚举常量
int array1[SIZE1];
int array2[SIZE2];
};
枚举常量不会占用对象的存储空间,它在编译时被全部求值。
4.2 const成员函数
任何不会修改类得数据成员的函数都应该声明为const类型,而任何const类型成员函数,不得修改数据成员和调用非const类型的成员函数。类似于static成员函数只能使用static数据成员和调用static成员函数。
注意:在const成员函数的声明与定义中,const关键字放在最后的。
class A
{
public:
void fun1() const;//const成员函数声明
};
A::fun1() const
{
...........; //不能改变数据成员,不能调用非const成员函数
}
5.const修饰对象/对象指针/对象引用
任何const对象只能使用const成员函数,不能调用非const成员函数,因为非const成员函数有可能改变数据成员。const对象指针/对象引用类似。
class A
{
public:
void fun1();
void fun2() const;
};
A::fun1()
{
}
A::fun2() const
{
}
void main(void)
{
const A a;
a.fun1(); //错误,const对象调用非const成员函数
a.fun2(); //正确
}