📄 8815.htm
字号:
<HTML>
<HEAD>
<meta http-equiv='Content-Type' content='text/html; charset=gb2312'>
<style >
.fst{padding:0px 15px;width:770px;border-left:0px solid #000000;border-right:0px solid #000000}
.fstdiv3 img{border:0px;border-right:8px solid #eeeecc;border-top:6px solid #eeeecc}
</style>
<title>
Effective C++ 2e Item21
</title>
</HEAD>
<BODY >
<center>
<div align=center><div class=fst align=left><div class=fstdiv3 id=print2>
<b>
Effective C++ 2e Item21
</b><p>条款21: 尽可能使用const</p>
<p>使用const的好处在于它允许指定一种语意上的约束——某种对象不能被修改——编译器具体来实施这种约束。通过const,你可以通知编译器和其他程序员某个值要保持不变。只要是这种情况,你就要明确地使用const ,因为这样做就可以借助编译器的帮助确保这种约束不被破坏。</p>
<p>const关键字实在是神通广大。在类的外面,它可以用于全局或名字空间常量(见条款1和47),以及静态对象(某一文件或程序块范围内的局部对象)。在类的内部,它可以用于静态和非静态成员(见条款12)。</p>
<p>对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const,还有,两者都不指定为const:</p>
<p>char *p = "hello"; // 非const指针,<br> // 非const数据</p>
<p>const char *p = "hello"; // 非const指针,<br> // const数据</p>
<p>char * const p = "hello"; // const指针,<br> // 非const数据</p>
<p>const char * const p = "hello"; // const指针,<br> // const数据</p>
<p>语法并非看起来那么变化多端。一般来说,你可以在头脑里画一条垂直线穿过指针声明中的星号(*)位置,如果const出现在线的左边,指针指向的数据为常量;如果const出现在线的右边,指针本身为常量;如果const在线的两边都出现,二者都是常量。</p>
<p>在指针所指为常量的情况下,有些程序员喜欢把const放在类型名之前,有些程序员则喜欢把const放在类型名之后、星号之前。所以,下面的函数取的是同种参数类型:</p>
<p>class widget { ... };</p>
<p>void f1(const widget *pw); // f1取的是指向<br> // widget常量对象的指针</p>
<p>void f2(widget const *pw); // 同f2</p>
<p>因为两种表示形式在实际代码中都存在,所以要使自己对这两种形式都习惯。</p>
<p>const的一些强大的功能基于它在函数声明中的应用。在一个函数声明中,const可以指的是函数的返回值,或某个参数;对于成员函数,还可以指的是整个函数。</p>
<p>让函数返回一个常量值经常可以在不降低安全性和效率的情况下减少用户出错的几率。实际上正如条款29所说明的,对返回值使用const有可能提高一个函数的安全性和效率,否则还会出问题。</p>
<p>例如,看这个在条款19中介绍的有理数的operator*函数的声明:</p>
<p>const rational operator*(const rational& lhs,<br> const rational& rhs);</p>
<p>很多程序员第一眼看到它会纳闷:为什么operator*的返回结果是一个const对象?因为如果不是这样,用户就可以做下面这样的坏事:</p>
<p>rational a, b, c;</p>
<p>...</p>
<p>(a * b) = c; // 对a*b的结果赋值</p>
<p>我不知道为什么有些程序员会想到对两个数的运算结果直接赋值,但我却知道:如果a,b和c是固定类型,这样做显然是不合法的。一个好的用户自定义类型的特征是,它会避免那种没道理的与固定类型不兼容的行为。对我来说,对两个数的运算结果赋值是非常没道理的。声明operator*的返回值为const可以防止这种情况,所以这样做才是正确的。</p>
<p>关于const参数没什么特别之处要强调——它们的运作和局部const对象一样。(但,见条款m19,const参数会导致一个临时对象的产生)然而,如果成员函数为const,那就是另一回事了。</p>
<p>const成员函数的目的当然是为了指明哪个成员函数可以在const对象上被调用。但很多人忽视了这样一个事实:仅在const方面有不同的成员函数可以重载。这是c++的一个重要特性。再次看这个string类:</p>
<p>class string {<br>public:</p>
<p> ...</p>
<p> // 用于非const对象的operator[]<br> char& operator[](int position)<br> { return data[position]; }</p>
<p> // 用于const对象的operator[]<br> const char& operator[](int position) const<br> { return data[position]; }</p>
<p>private:<br> char *data;<br>};</p>
<p>string s1 = "hello";<br>cout << s1[0]; // 调用非const<br> // string::operator[]<br>const string s2 = "world";<br>cout << s2[0]; // 调用const<br> // string::operator[]</p>
<p>通过重载operator[]并给不同版本不同的返回值,就可以对const和非const string进行不同的处理:</p>
<p>string s = "hello"; // 非const string对象</p>
<p>cout << s[0]; // 正确——读一个<br> // 非const string</p>
<p>s[0] = 'x'; // 正确——写一个<br> // 非const string</p>
<p>const string cs = "world"; // const string 对象</p>
<p>cout << cs[0]; // 正确——读一个<br> // const string</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -