effective c++(03)之const使用方法
char greeting[] = "hello"; char* p = greeting; //non-const pointer,non-const data const char* p = greeting; //non-const pointer, const data char* const p = greeting; //const pointer,non-const data const char* const p = greeting; //const pointer, const data
以上为const面对指针时所产生的四种情况。
const 如出现在星号左边,表示被指物是常量;如果出现在星号右边,表示指针本身是常量;如果出现在星号两边,表示被指物和指针都是常量。
如果被指物是常量,const写在类型之前和类型之后都可以,意义相同,一下两种写法相同:
void f1( const type* pw ); void f2( type const* pw );
而对于STL迭代器。所有的迭代器作用就跟T*一样。声明迭代器为const就像声明一个const指针一样,表明迭代器不能指向不同的东西。如果想让迭代器指向的东西不可改变,则需要声明const_iterator。如下:
const vector<int>::iterator iter = vec.begin(); //如 T* const *iter = 10; //没有问题 iter++; //不可执行 vector<int>::const_iterator citer = vec.begin(); //如 const T* *citer = 10; //不可执行 citer++; //可以
const最具有威力的用法是面对函数声明时的应用:
class Rational {...}; const Rational operator* ( const Rational& lhs, const Rational& rhs); Rational a,b,c; ... (a*b)=c;
如以上例子,对两个数值的乘积做了一次赋值,将operator*的回传声明为const可以预防这种没有意思的动作。
const成员函数
如果函数的返回类型是内置类型,那么如果改动函数返回值从来就不合法。如果返回类型为引用,则可以给返回值赋值。
class TextBlock{ public: const char& operator[]( size_t position ) const { return text[position]; } char& operator[](size_t position) { return text[position]; } private: string text; };
如上类中,如果有以下调用:
TextBlock tb("hello"); cout << tb[0]; const TextBlock ctb("world"); cout << ctb[0];
tb直接调用类中的non-const成员函数,ctb调用的是const成员函数,如下代码:
cout << tb[0]; tb[0] = 'x'; cout << ctb[0]; ctb[0] = 'x';
ctb[0]='x'是不可以被执行的,因为const成员函数返回的是const的引用,并且const成员函数所使用的数据成员不可以被更改。
但是由于以上的方法却产生了以下问题:
class CTextBlock{ public: char& operator[]( size_t position ) const { return pText[position]; } private: char* pText; };
对于以上的类在如下调用时:
const CTextBlock cctb("hello"); char* pc = &cctb[0]; *pc = 'J';
此时cctb为‘Jello’。
以上为 bitwise const 的观点,虽然const成员对象没有改变类的数据成员,但是整体上是改变了,这样的情况下const类成员意义不大,终究还是改变了其值。
于是产生了logical constness的观点:
class CTextBlock{ public: size_t length() const; private: char* pText; size_t textLength; bool lengthIsValid; }; size_t CTextBlock::length() const { textLength = strlen(pText); lengthIsValid = true; return textLength; }
以上代码显然没法执行,因为在length为const成员函数不能改变数据成员。logical constness的观点如下:
class CTextBlock{ public: size_t length() const; private: char* pText; mutable size_t textLength; mutable bool lengthIsValid; }; size_t CTextBlock::length() const { textLength = strlen(pText); lengthIsValid = true; return textLength; }
在const成员函数前加上mutable即可实现const成员函数改变数据成员。