一、const修饰指针
const修饰指针时,可以修饰其指针本身,指针所指物或这两者都修饰。
虽然看似情况挺多,但要区分并不难。如果关键字const出现在星号 * 的左边,表示被指物是个常量,不能通过指针修改所指物;如果出现在 * 右边,则表示指针是一个常指针,不能修改其指向。如果出现在 * 两边,表示被指物和指针都是常量。
结合下面的例子理解:
int a = 5, b = 3;
const int* p = &a; //p指向的值是个常量,不能通过p修改对象
p = &b; //没问题,可以修改指针p的指向
int* const q = &a; //q是个常指针,不能修改其指向
*q = 10; //没问题,可以通过q修改对象
另提一件事,关键字const在类型前(肯定在星号前了),或是类型后,星号前。两种写法意义相同,都是表示指向一个常量。两种形式都有人在用,应当习惯它们。
void f1(const int* pi);
void f2(int const * pi);
二、const修饰迭代器
STL迭代器也是以指针实现的,跟指针一样有修饰其指向、指针所指物或都修饰。而STL中模拟的有const 修饰其所指物,是const_iterator。
结合下面的例子理解:
std::vector<int> vec;
……
const std::vector<int>::iterator iter = //iter的作用如同T* const
vec.begin();
*iter = 10; //没问题,改变iter所指物
iter++; //错误,iter本身是const
std::vector<int>::const_iterator cIter = //citer的作用如同const T*
vec.begin();
*cIter = 10; //错误,*cIter是const
cIter++; //没问题,改变cIter指向
三、const修饰函数
1.const修饰返回值
令函数返回一个常量值,往往可以降低印客户错误而造成的意外。
结合下面的例子理解:
class Rational {……};
const Rational operator* (const Rational& lhs, const Rational& rhs);
Rational a, b, c;
if (a * b = c) {……} //这种赋值操作,许多人会因为打错,本意是
如果不返回一个const对象,那么上面对 乘积 的赋值操作,就会通过编译,"无意"中的错误就难以发现。而返回const值,就可以避免这个“没意义的赋值动作”。
2.const修饰类的成员函数
目的是确认该const成员函数作用于const对象,不可改变对象的值。const成员函数重要的理由:
- class接口比较容易被理解。知道那个函数可以修改对象内容,那个函数不行,很是重要。
- 使"操作const对象"成为可能。因为const对象只能调用const成员函数,但是非const对象既可以调用普通成员函数,也可以调用const成员函数。这是因为this指针可以转换为const this,但是const this不能转换为非const this。
还有一件被漠视的事实:const成员函数于非const函数发生重载。
结合下面的例子理解:
class TextBlock()
{
public:
TextBlock(string str):text(str) {} //构造函数
const char& operator[] (size_t positin) const
{ return text[position]; }
char& operator[] (size_t positin)
{ return text[position]; }
private:
string text;
}
TextBlock tb("Hello");
std::cout << tb[0]; //调用非const TextBlocks::operator[]函数
const TextBlock ctb("World");
std::cout << ctb[0]; //调用const TextBlocks::operator[]函数
ctb[0] = 'w'; //错误,不能够修改const返回值
四、请记住
- 将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
- 编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”(conceptual constness)。
- 当const 和非const成员函数有着实质等价的实现时,令非const版本调用const版本可避免代码重复。