本文转载自:http://www.cnblogs.com/AnnieKim/archive/2011/11/22/2258946.html
作者:金玉姬
1) 声明及初始化const常量。
在声明一个const常量时,必须对其初始化,否则会报错。
1 const int constvar; //error 2 const int constvar = 10; //ok
但是,有一个例外的情况,就是extern进来的const常量不需要初始化(如果该常量其他地方确实有出现,这时将它extern进来并且初始化反而会出错)。
1 extern const int externvar;
2) 指针。
对于指针变量有以下四种情况(这四句是不完整的,其中有些必须在声明时进行初始化,否则会出错,故未写分号^^):
a int *ptr1 b const int *ptr2 c int *const ptr3 d const int *const ptr4
a) 指向非const对象的指针。
试图将非const对象的指针指向一个常量对象将引起编译错误,即下面的语句将不能通过编译。
1 int *ptr1 = &constvar; //error
原因很简单。如果可以编译成功,我们则可以通过类似*ptr1=100这样的语句修改constvar常量的值(由于编译器不能跟踪指针在程序中任意一点指向的对象是否为常量,所以是可以赋值成功的)。这样一来就不能称之为常量了。
b) 指向const对象的指针。
与a做对比,此时由于ptr2指向的是一个const常量,所以就可以将它赋值为const常量的地址了。
1 const int *ptr2 = &constvar; //ok
此时,由于ptr2指向的对象是常量,所以不能通过指针修改常量的值。但是,由于指针本身不是常量,所以可以修改指针,令其指向其他常量,甚至可以令其为0。
1 *ptr2 = 100; //error 2 const int constvar2 = 100; 3 ptr2 = &constvar2; //ok 4 ptr2 = 0; //ok
另外,也可以令ptr2指向一个变量(非常量),但是也同样,不能通过指针修改变量的值,如下:
1 int nonconst = 1000; 2 ptr2 = &nonconst; //ok 3 *ptr2 = 10000; //error
c) const指针,指向const或非const对象。
声明const指针时,必须同时对其进行初始化。
1 int nonconst = 1000; 2 int *const ptr3; //error 3 int *const ptr3 = &nonconst; //ok
如果,ptr3指向的是一个非const对象,可以通过ptr3修改该对象的值,但是不能修改ptr3指针本身的值,如下:
1 *ptr3 = 10000; //ok 2 ptr3 = &constvar; //error
d) 指向const对象的const指针。
终于最后一个了。这种指针,就是把前面的几个结合起来。声明时必须初始化,指针指向的对象以及指针本身都不能修改。
3) 迭代器。
const_iterator用于遍历const容器。
1 const vector<int> constvector; 2 vector<int>::iterator it = constvector.begin(); //error 3 vector<int>::const_iterator it = constvector.begin(); //ok
const_iterator保证是以只读的方式访问容器元素,不得通过迭代器修改容器元素的值。
1 *it = 20; //error
4) 函数参数。
参数传值还是传指针还是传引用的问题这里就不啰嗦了。
当参数为引用时,如果不希望引用参数在被调用的函数内部被修改,就可以使用const修饰符修饰引用参数。
1 void func(const int& var) 2 { 3 var = 100; //error 4 }
用const修饰传值参数是没有任何意义的,因为传值本身就是传入一个实参的副本,并不会修改实参(刚入职时,我就犯了这个低级的错误--|)。
5) const成员函数。
在有些类的成员函数中,往往会看到在参数列表的最后有一个const修饰符,形如:
1 class test 2 { 3 public: 4 int getVar() const 5 { 6 return var; //ok 7 } 8 void setVar(const int& aVar) const 9 { 10 var = aVar; //error 11 } 12 13 private: 14 int var; 15 };
a) 用const修饰成员函数,表明不能通过调用该成员函数修改类对象。如上例中setVar函数由于修改了test类中的var成员变量,所以不能使用const限定符修饰。
b) 对于在类外定义的成员函数,必须在成员函数的定义和声明中都指定关键字const,不然将被视为重载,如下:
1 class test 2 { 3 public: 4 int getVar() const; 5 private: 6 int var; 7 }; 8 9 int test::getVar() //error:overloaded member function not found in 'test' 10 { 11 return var; 12 }
c) const类对象只能调用其const成员函数(除了构造函数和析构函数,后面详解)。
1 class Test 2 { 3 public: 4 int getVar(){ return var; } 5 private: 6 int var; 7 }; 8 9 int main() 10 { 11 const Test consttest; 12 consttest.getVar(); //error 13 14 return 0; 15 }
第12行语句将报错,由于Test类并没有定义一个const版本的getVar()成员函数。
但是,这种情况有一个例外,就是构造函数和析构函数。即使构造函数和析构函数不是const的,const类对象也同样可以调用它们。所以一个const类对象“从构造完成时刻到析构开始时刻”这段时间被认为是const的(尝试将构造函数写为const,不过报错了)。
d) 如果一个类含有指针,那么在const成员函数中还是可以修改指针所指的对象。其实想想这句话也比较好理解,指针的值是不能修改的,但是指针所指的对象是可以修改的。