顺便说一下,在真实的程序中, const 对象在大多数情况下都以“通过指针传递”或“引用一个 const ”的形式出现。 上面的 ctb 的例子纯粹是人为的,而下面的例子在真实状况中常会出现:
void print(const TextBlock& ctb) // 在这个函数中 ctb 是 const 的
{
std::cout << ctb[0]; // 调用 const 的 TextBlock::operator[]
...
}
通过对 operator[] 的重载以及为每个版本提供不同类型的返回值,你便可以以不同的方式处理 const 的或者非 const 的 TextBlock :
std::cout << tb[0]; // 正确:读入一个非 const 的 TextBlock tb [0] = 'x'; // 正确:改写一个非 const 的 TextBlock std::cout << ctb[0]; // 正确:读入一个 const 的 TextBlock ctb [0] = 'x'; // 错误 ! 不能改写 const 的 TextBlock
请注意,这一错误只与所调用的 operator[] 的返回值的类型有关,如果仅仅调用 operator[] 本身则不会出现任何问题。错误出现在:企图为一个 const char& 赋值,而 const char& 则是 operator[] 的 const 版本的返回值类型。
同时还要注意的是,非 const 的 operator[] 的返回值类型是一个 char 的引用,而不是 char 本身。如果 operator[] 真的简单的返回一个 char ,那么下面的语句将不能正确编译:
tb[0] = 'x';
这是因为,企图修改一个返回内建数据类型的函数的返回值根本都是非法的。即使假设这样做合法,而 C++ 是 通过传值返回对象的,所修改的仅仅是由 tb.text[0] 复制出的一份副本,而不是 tb.text[0] 本身,你不会得到预期的效果。
让我们暂停一小会儿,来考虑一下这里边的哲学问题。把一个成员函数声明为 const 的有什么涵义呢?这里有两个流行的说法:按位恒定(也可叫做物理恒定)和逻辑恒定。
按位恒定阵营坚信:当且仅当一个成员函数对于所有对象的数据成员( static 数据成员除外)都不做出改动时,才需要将这一成员函数声明为 const 的,换句话说,将成员函数声明为 const 的条件是:成员函数不对对象内部做任何的改动。按位恒定的好处之一就是,它使得错误检查便得更轻松:编译器仅需要查找对数据成员的赋值。实际上,按位恒定就是 C++ 对于恒定的定义,如果一个 const 的成员函数调用了某个对象,那么即使该对象拥有非静态数据成员,其所有数据成员也都是不可修改的。
不幸的是,大多数不完全是 const 的成员函数也可以通过按位恒定的检验。在特定的情况下,如果一个成员函数频繁的修改一个指针所指的位置,那么我们说它就不是一个 const 的成员函数。但是只要这个指针存在于一个对象中,这个函数就是按位恒定的,这时候编译器不会报错。这样会导致编成的行为不符合常规习惯。比如说,我们手头有一个类似于 TextBlock 的类,其中保存着 char* 类型的数据而不是 string ,因为这段代码有可能要与一些 C 语言的 API 交互,但是 C 语言中没有 string 对象一说。
本文来自电脑杂谈,转载请注明本文网址:
http://www.pc-fly.com/a/jisuanjixue/article-62399-3.html
只有成大神才有钱拿