const修饰符就是为了将变量声明为不可变的常量,使程序更加的健壮。
(1)为什么define应该用const enum inline来替代(effective C++):
const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换时可能会产生意料不到的错误(边际效应) 。
define作用于预编译阶段,也就是说在预编译阶段把所有define的常量替换为相应字符,常量没有进入符号表,这样如果出错编译器只会提示相应字符出错不会 不好进行判断,所以define声明的常量应该用const或者枚举替代来声明常量,这样才能加入到字符表,出错很容易调试。
define声明的形式函数的宏,应该用inline 模板函数进行替代,因为宏不具有安全性,其并不是一个统一的整体,应用内联函数替代。
小插曲,enum与const定义常量是的优缺点:const与enum各有优缺点,最大的区别就是enum只能用于定义整数,而不能定义浮点数;而对于定义逻辑关系较近的一组符号常量时比较适合使用enum,不适合使用const.
(2)const修饰类的数据成员:
class A
{
const int size;
…
}
const 数据成员只在某个对象生存期内是常量,而对于整个类而言却是可变的。因为类可以创建多个对象,不同的对象其const数据成员的值可以不同。所以不能在类 声明中初始化const数据成员,因为类的对象未被创建时,编译器不知道const 数据成员的值是什么。如
class A
{
const int size = 100; //错误
int array[size]; //错误,未知的size
}
const数据成员的初始化只能在类的构造函数的初始化表中进行。要想建立在整个类中都恒定的常量,应该用类中的枚举常量来实现。如
class A
{…
enum {size1=100, size2 = 200 };
int array1[size1];
int array2[size2];
}
枚举常量不会占用对象的存储空间,他们在编译时被全部求值。但是枚举常量的隐含数据类型是整数,其最大值有限,且不能表示浮点数。
(3)const修饰类的成员函数:
一般放在函数体后,形如:void fun() const;
任何不会修改数据成员的函数都因该声明为const类型。如果在编写const成员函数时,不慎修改了数据成员,或者调用了其他非const成员函数,编译器将报错,这大大提高了程序的健壮性。l另外,const修饰的成员函数只能调用const成员函数如:
class Stack
{
public:
void Push(int elem);
int Pop(void);
int GetCount(void) const; //const 成员函数
private:
int m_num;
int m_data[100];
};
int Stack::GetCount(void) const
{
++m_num; //编译错误,企图修改数据成员m_num
Pop(); //编译错误,企图调用非const函数
Return m_num;
}
(4)const对象:
常对象是指对象的数据成员的值在对象被调用时不能被改变。常对象必须进行初始化,且不能被更新。不能通过常对象调用普通成员函数,但是可以通过普通对象调用常成员函数。常对象只能调用常成员函数。
class A{
private:
int w,h;
public:
int getArea() const
{
return w*h;
}
int getW(){ return w;}
void setWH(int x,int y) {w=x,h=y;}
A(int x,int y){w=x,h=y;}
A(){;}//本例中不能省略
};
void main()
{
A a;//非常对象可以不初始化
a.setWH(3,9);
A const b; //常对象必须声明的同时初始化,正确的是 A const b(3,6)。
b.setWH(3,7); // 假如上面改正后用这一句,还是错误应为b是常对象不能调用非常成员函数,切其值调用时不能改变,setWH()
cout<< a.getArea()<<endl<< b.getArea()<<c.getArea();
system("pause");
也就是说常对象在初始化的时候必须通过构造函数进行初始化,并且const对象只能调用cosnt函数,这样可以保证其健壮性,确保const对象没有对
数据成员进行任何的修改。
(5)const 修饰指针:
如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向为常量;如果const位于星号的 右侧,const就是修饰指针本身,即指针本身是常量(efficetve C++)。
(6) const 修饰函数:
i:const修饰函数参数,此处需要谨记就是说内置数据类型(如int double char等)应该直接用值传递的方式,这样简单易懂,效率高(函数内部维持此变量的拷贝);如果为非内置数据类型,如struct或class等,函数传参应该是const 指针 或者cosnt 引用,最好用const引用,因为引用比指针更加的安全。如void Func(A a)改为void Func(const A &a) 或者Func(const A* a).(当然此处有一个前提就是传递过来的参数不进行改变才加const,如果改变的话就不加const修饰符)。
ii:const修饰函数返回值。只需要考虑特殊的返回const指针这种情况。如果给采用“指针传递”方式的函数返回值加const修饰,那么函数返回值(即指针)的内容不能被修改,该返回值只能被赋给加const 修饰的同类型指针。onst char * GetString(void);
如下语句将出现编译错误:
char *str=GetString();
正确的用法是:
const char *str=GetString();
同时,str指针可以指向其他字符串,但是*str的值不能被修改。