const是一种约束,告诉编译器和其他程序员,这个值不要被修改。
a.函数返回值是常量: 例如有理数的乘法重载:
const Rational operator* (const Rational& lhs, const Rational& rhs);
这样写可以避免一些暴行,例如
Rational a, b, c;
(a * b) = c;
b.const成员函数
将const实施于成员函数的目的,是为了确认改成员函数可作用于const对象身上。
两个成员函数如果只是常量性不同,可以被重载。例如:
using std::cout;
using std::endl;
using std::string;
class TextBlock
{
public:
const char& operator[](std::size_t position) const
{
cout << "const版本" << endl;
return text[position];
}
char& operator[](std::size_t position)
{
cout << "普通版本" << endl;
return text[position];
}
TextBlock(const string& s) :text{ s }
{
}
private:
std::string text;
};
void print(const TextBlock& tb)
{
cout << tb[0] << endl;
}
int main()
{
TextBlock tb{ "Hello" };
cout << tb[0] << endl; // 普通版本
const TextBlock ctb{"World"};
cout << ctb[0] << endl; // const普通版本
print(TextBlock{ "OhGod" }); // const普通版本
}
此小节也引出了mutable关键字。
c.在const和non-const成员函数中避免重复
上面的类中,constt版本和non-const版本在实际的代码中可能会有大量相同的代码,所以如果像重载一样,能让non-const版本调用const版本,
将会减少很多重复代码:
char& operator[](std::size_t position)
{
return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]);
//cout << "普通版本" << endl;
//return text[position];
}
先将*this转换成const对象,然后就可以调用const版本的[],最后将返回值去const。
但是如果反过来,用const版本调用non-const是肯定不行的,因为const承诺不改变对象的逻辑状态。
总结
a.将某些东西声明为const可以帮助编译器侦测出错误语法。const可被施加于任何作用于内的对象、函数参数、函数返回类型、成员函数本体。
b.编译器强制实施bitwise constness,但你编写程序时应该使用“概念上的常量性”(conceptual constness)。
c.当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复。