1. 将某些东西声明为 const 可帮助编译器侦测出错误用法;
2. const 尽可能地被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体;
3. 要注意下面”const 成员函数,案例一“中的情况;
4. 当 const 和 non-const 成员函数有着实质等价的实现时,令 non-const 版本调用 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 出现在星号两边,表示被指物和指针两者都是常量。
注意: 如果被指物是常量,有些程序员会将关键字 const 写在类型之前,有些人会把它写在类型之后、星号之前。两种写法的意义相同,所以下列两个函数接受的参数类型是一样的:
void f1(const Widget* pw); // f1获得一个指针,指向一个常量的(不变的)Widget对象
void f2(Widget const * pw); // 与f1相同
STL迭代器
STL迭代器系以指针为根据塑模出来,所以迭代器的作用就像个 T* 指针。声明迭代器为 const 就像声明指针为 const 一样(即声明一个 T* const 指针),表示这个迭代器不得指向不同的东西,但它所指的东西的值是可以改动的。如果你希望迭代器所指的东西不可被改动(即希望STL模拟一个 const T* 指针),你需要的是 const_iterator:
std::vector<int> vec;
...
const std::vector<int>::iterator iter = vec.begin(); // iter的作用像个T* const
*iter = 10; // ok!改变iter所指物
++iter; // error!iter是const
std::vector<int>::const_iterator cIter = vec.begin(); //cIter的作用像个const T*
*cIter = 10; // error!*cIter是const
**cIter; // ok!改变cIter
const 成员函数
将 const 用于成员函数的目的,是为了确认该成员函数可作用于 const 对象身上。
-
const 成员函数重要的原因:
① 使 class 接口比较容易被理解。这是因为,得知哪个函数可以改动对象内容而哪个函数不行,很是重的。
② 它们使“操作const对象”成为可能,使得更高效地编写代码。 -
引入 mutable
成员函数只有在不更改对象之任何成员变量(static除外)时才可以说是 const。
若想让某个非 static 成员变量的值能被 const 成员函数修改,可以使用mutable
。案例一:
class CTextBlock { public: ... // 该成员函数是const,函数内没有修改pText的指向,因此编译能通过。 char& operator[] (std::size_t position) const { return pText[position]; } private: char* pText; }
const CTextBlock cctb("Hello"); // 声明一个常量对象 char* pc = &cctb[0]; // 调用operator[]取得一个指针,指向cctb的数据 *pc = 'J'; // 修改了cctb的数据
案例二:
class CTextBlock { public: ... std::size_t length() const; private: char* pText; mutable std::size_t textLength; // const成员函数也可改变其值 mutable bool lengthIsValid; // const成员函数也可改变其值 }; std::size_t CTextBlock::length() const { if(!lengthIsValid) { textLength = std::strlen(pText); lengthIsValid = true; } return textLength; }
-
在 const 和 non-const 成员函数中避免重复
下面这段代码会有很多重复的部分,增加了编译、维护时间,有代码膨胀现象。class TextBlock { public: ... const char& operator[](std::size_t position) const { ... // 操作一 ... // 操作二 return text[position]; } char& operator[](std::size_t position) { ... // 操作一 ... // 操作二 return text[position]; } private: std::string text; }
因此,可以用 non-const 的函数调用 const 的函数,减少重复代码。
class TextBlock { public: ... const char& operator[](std::size_t position) const { ... // 操作一 ... // 操作二 return text[position]; } // 调用const的成员函数 char& operator[](std::size_t position) { return const_cast<char&>( // 将op[]返回值的const转除 static_cast<const TextBlock&>(*this) // 为*this加上const [position] // 调用const op[] ); } ... }
注意: 不可使用 const 的函数调用 non-const 的函数!!!因为,使用 const 成员函数的目的是确保函数不会修改成员变量的值,而 non-const 成员函数可修改成员变量的值。若在 const 函数内调用 non-const 就会产生矛盾。相反,non-const 函数调用 const 函数不会出现这种问题。
评论区