C++箴言:只要可能就用const(二)

2014-11-24 13:16:33 · 作者: · 浏览: 16
- writing a
// non-const TextBlock

std::cout << ctb[0]; // fine - reading a
// const TextBlock

ctb[0] = ’x’; // error! - writing a
// const TextBlock
  请注意这个错误只是发生在调用 operator[] 的返回类型上,而调用 operator[] 本身总是正确的。错误出现在企图为 const char& 赋值的时候,而这正是 const 版本的 operator[] 的返回类型。

  再请注意 non-const 版本的 operator[] 的返回类型是一个字符的引用而不是字符本身。如果 operator[] 只是简单地返回一个字符,下面的语句将无法编译:

tb[0] = ’x’;
  因为改变一个返回内建类型的函数的返回值总是非法的。如果它合法,那么 C++ 以值(by value)返回对象这一事实(参见 Item 20)就意味着 tb.text[0] 的副本被改变,而不是 tb.text[0] 自己,这不会是你想要的行为。

  让我们为哲学留一点时间。看看一个成员函数是 const 意味着什么?有两个主要的概念:二进制位常量性(bitwise constness)(也称为物理常量性(physical constness))和逻辑常量性(logical constness)。

  二进制位 const 派别坚持认为,一个成员函数,当且仅当它不能改变对象的任何数据成员(static 成员除外),也就是说不能改变对象内的任何二进制位,则这个成员函数就是 const。二进制位常量性的一个好处是比较容易监测违例:编译器只需要寻找对数据成员的赋值。实际上,二进制位常量性就是 C++ 对常量性的定义,一个 const 成员函数不被允许改变调用它的对象的任何 non-static 数据成员。
不幸的事,很多成员函数并不能完全通过二进制位常量性的检验。特别是,一个经常改变一个指针指向的内容的成员函数。除非这个指针在这个对象中,否则这个函数就是二进制位 const 的,编译器也不会提出异议。例如,假设我们有一个类似 TextBlock 的类,因为它需要与一个不知 string 为何物的 C API 打交道,所以它需要将它的数据存储为 char* 而不是 string。

class CTextBlock {
  public:
   ...
   char& operator[](std::size_t position) const // inappropriate (but bitwise

   { return pText[position]; } // const) declaration of
   // operator[]
  private:
   char *pText;
};

  尽管 operator[] 返回对象内部数据的引用,这个类还是(不适当地)将它声明为 const 成员函数(Item 28 将谈论一个深入的主题)。先将它放到一边,看看 operator[] 的实现,它并没有使用任何手段改变