条款03: 尽可能使用 const
1.const 的一些用法和好处
a) 指针
关键字const出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针自身是常量;如果出现在两边,表示被指物和指针两者都是常量。
* const //被指物是常量
const * //指针自身是常量
* const * // 以上全是常量
void f1(const Widget* pw);
void f2(Widget const* pw); // 俩种写法等价
b) STL
如果想要STL 模拟一个const T* 指针,需要const_iterator。
const std::vector<int>::iterator iter = vec.begin(); //iter是个常量
std::vector<int>::const_iterator cIter = vec.begin(); //cIter所指物是个常量
c) 函数
在函数面前加入const 可以在编译的时候就发现一些错误。比如把'=='意外写成'='的错误。
Rational a,b,c;
if(a * b = c) //运算符重载
2.const成员函数
1.两个成员函数如果是常量性不同,就会发生重载。
class TextBlock{
public:
...
const char& operator[](std::size_t position) const
{ return text[position]; }
char& operator[](std::size_t position)
{ return text[position]; }
private:
std::string text;
};
TextBlock tb("hello");
std::cout << tb[0]; //调用的是non-const TextBlock::operator[]
const TextBlock ctb("hello");
std::cout << ctb[0]; //调用的是const TextBlock::opeartor[]
2.函数的尾部加入了const,内部不能出现赋值操作,要想改变需要使用mutable关键字。
class CTextBlock {
public:
...
std::size_t length() const;
private:
char* pText;
mutable std::size_t testLength;
bool lengthIsVaild;
};
std::size_t CTextBlock::length() const
{
if (!lengthIsVaild){
textLength = std::strlen(pText); //可行
lengthIsVaild = true; // 报错
}
return textLength;
}
3.在 const 和 non-const 成员函数汇总避免重复
class TextBlock {
public:
...
const char& operator[](std::size_t position) const
{
...
...
...
return text[position];
}
char& operator[](std::size_t position)
{
return const_cast<char&>(static_cast<const TextBlock&>(*this))[position]);
}
其中做了俩个转型操作,第一个是static_cast将 *this 也就是该类转换为const类型,然后再调用const 类型的成员函数,第二个转型将返回值,const char& 转换为 char& 这样也就避免了函数的重复。
总结
将某些东西声明为 const 可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
编译器强制实施 bitwise constness,但你编写程序时应该使用“概念上的常量性”(conceptual constness)。
当const 和 non-const 成员函数有着实质等价的实现时,令 non-const 版本调用 const 版本可避免代码重复。