读书笔记《Effective C++》条款03:尽可能使用const
来源:互联网 发布:万网域名证书生成 编辑:程序博客网 时间:2024/05/08 20:42
const允许你指定一个语义约束(也就是指定一个“不该被改动”的对象),而编译器会强制实施这项约束。它允许你告诉编译器和其他程序员某值应该保持不变。
可以用const在class外部修饰global或namespace作用域中的常量,或修饰文件、函数、或区块作用域(block scope)中被声明为static的对象。也可以用它修饰class内部的static和non-static成员变量。
面对指针,也可以指出指针自身、指针所指物,或两者都(或都不)是const:
char greeting[] = "Hello";char* p = greeting;//non-const pointer,non-const dataconst char* p = greeting;//non-const pointer,const datachar* const p = greeting;//const pointer,non-const dataconst char* const p = greeting;//const pointer,const data
const最具威力的用法是面对函数声明时的应用。在一个函数声明式内,const可以和函数返回值、各参数、函数自身(如果是成员函数)产生关联。
令函数返回一个常量值,往往可以降低因客户错误而造成的意外,而又不至于放弃安全性和高效性。
至于const参数,除非有需要改动参数或local对象,否则请将它们声明为const。
const成员函数
将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。这一类成员函数之所以重要,基于两个理由。第一,它们使class接口比较容易被理解。这是因为,得知哪个函数可以改动对象内容而哪个函数不行,很重要。第二,它们使“操作const对象”成为可能。
两个成员函数如果只是常量性(constness)不同,可以被重载。这是一个重要的C++特性。
class TextBlock {public:TextBlock(std::string text);const char& operator[](std::size_t position) const;//operator[] for const objectchar& operator[](std::size_t position);//operator[] for non-const objectprivate:std::string text;};TextBlock::TextBlock(std::string text){this->text = text;}const char& TextBlock::operator[](std::size_t position) const{std::cout << "const operator[]" << std::endl;return text[position];}char& TextBlock::operator[](std::size_t position){std::cout << "non-const operator[]" << std::endl;return text[position];}int _tmain(int argc, _TCHAR* argv[]){TextBlock tb("Hello");std::cout << tb[0] << std::endl;// call non-const TextBlock::operator[]const TextBlock ctb("World");std::cout << ctb[0] << std::endl;// call const TextBlock:operator[]system("pause");return 0;}const成员函数不能修改成员变量。例子如下:
class TextBlock {public:TextBlock(std::string text);const char& operator[](std::size_t position) const;//operator[] for const objectchar& operator[](std::size_t position);//operator[] for non-const objectprivate:std::string text;};TextBlock::TextBlock(std::string text){this->text = text;}const char& TextBlock::operator[](std::size_t position) const{std::cout << "const operator[]" << std::endl;text = "abcde";//编译错误:在const成员函数内不能对成员变量text赋值return text[position];}char& TextBlock::operator[](std::size_t position){std::cout << "non-const operator[]" << std::endl;text = "abcde";return text[position];}int _tmain(int argc, _TCHAR* argv[]){TextBlock tb("Hello");std::cout << tb[0] << std::endl;// call non-const TextBlock::operator[]const TextBlock ctb("World");std::cout << ctb[0] << std::endl;// call const TextBlock:operator[]system("pause");return 0;}
要解决这个问题,可以利用C++的一个与const相关的摆动场:mutable(可变的)释放掉non-static成员变量的bitwise constness约束:
class TextBlock {public:TextBlock(std::string text);const char& operator[](std::size_t position) const;//operator[] for const objectchar& operator[](std::size_t position);//operator[] for non-const objectprivate:mutable std::string text;//这些成员变量可能总是会被修改,即使在const成员函数内。};TextBlock::TextBlock(std::string text){this->text = text;}const char& TextBlock::operator[](std::size_t position) const{std::cout << "const operator[]" << std::endl;text = "abcde";//现在就可以在const成员函数内修改成员变量return text[position];}char& TextBlock::operator[](std::size_t position){std::cout << "non-const operator[]" << std::endl;text = "abcde";return text[position];}int _tmain(int argc, _TCHAR* argv[]){TextBlock tb("Hello");std::cout << tb[0] << std::endl;// call non-const TextBlock::operator[]const TextBlock ctb("World");std::cout << ctb[0] << std::endl;// call const TextBlock:operator[]system("pause");return 0;}
在const和non-const成员函数中避免重复
在上述例子中,假设TextBlock内的operator[]不单只是返回一个reference指向某字符,也执行边界检验、记录访问信息、甚至可能进行数据完善性检验。把所有这些同时放进const和non-const operator[]中,导致大量重复代码。当然,将这些重复代码移到另一个成员函数(往往是个private)并另两个版本的operator[]掉用它,是可能的,但还是重复了一些代码,例如函数调用、两次return语句等等。
真正该做的是实现operator[]的机能一次并使用它两次。也就是说,必须另其中一个调用另一个。这促使我们将常量性转除(casting away constness)。
本例中const operator[]完全做掉了non-const版本该做的一切,唯一的不同是其返回类型多了一个const资格修饰。这种情况下如果将返回值的const转除是安全的,因为不论谁调用non-const operator[]都一定首先有个non-const对象,否则就不能够调用non-const函数。所以另non-const operator[]调用其const兄弟是一个避免代码重复的安全做法——即使过程中需要一个转型动作。下面是代码:
class TextBlock {public:TextBlock(std::string text);const char& operator[](std::size_t position) const;//operator[] for const objectchar& operator[](std::size_t position);//operator[] for non-const objectprivate:std::string text;};TextBlock::TextBlock(std::string text){this->text = text;}const char& TextBlock::operator[](std::size_t position) const{std::cout << "const operator[]" << std::endl;return text[position];}char& TextBlock::operator[](std::size_t position){std::cout << "non-const operator[]" << std::endl;returnconst_cast<char&>(//将operator[]返回值的const转除static_cast<const TextBlock&>(*this)//为*this加上const[position]//调用const operator[]);}
如上述代码,这份代码又两个转型动作,而不是一个。我们打算让non-const operator[]调用其const operator[]兄弟,但non-const operator[]内部若只是单纯调用operator[],会递归调用自己。为了避免无穷递归,我们必须明确指出调用的是const operator[],但C++缺乏直接的语法可以那么做。因此这里将*this从其原始类型TextBook&转型为const TextBlock&。是的,我们使用转型操作为它加上const!所以这里共有两次转型:第一次用来为*this添加const(这使接下来调用operator[]时得以调用const版本),第二次则是从const operator[]的返回值中移除const。
添加const的那一次转型强迫进行了一次安全转型(将non-const对象转为const对象),所以我们使用static_cast。移除const的那个动作只可以藉由const_cast完成。
更值得了解的是,反向做法——令const版本调用non-const版本以避免重复。记住,const成员函数承诺绝不改变其对象的逻辑状态,non-const成员函数却没有这般承诺。如果在const函数内调用non-const函数,就是冒了这样的风险:你曾经承诺不改动的那个对象被改动了。这就是为什么”const成员函数调用non-const成员函数“是一种错误行为:因为对象有可能因此被改动。实际上若要令这样的代码通过编译,你必须使用一个const_cast将*this身上的const性质解放掉。non-const成员函数本来就可以对其对象做任何动作,所以在其中调用一个const成员函数并不会带来风险。这就是为什么本例以static_cast作用于*this的原因:这里并不存在const相关风险。
总结:const使用范围很广,在指针和迭代器身上;在指针、迭代器及reference指涉的对象身上;在函数参数和返回类型身上;在local变量身上;在成员函数身上,林林总总不一而定。尽可能使用它。
要点:
1.将某些东西声明为const可帮助编译器侦测出错误用法。const可被施加于在任何作用域内的对象、函数参数、函数返回类型、成员函数本体。
2.编译器强制实施bitwise constness,但你编写程序时应该使用”概念上的常量性“(conceptual constness)。
3.当const和non-const成员函数有着实质等价的实现时,另non-const版本调用const版本可避免代码重复。
- 读书笔记《Effective C++》条款03:尽可能使用const
- 【Effective C++】条款03-尽可能使用const
- Effective C++:条款03:尽可能使用const
- [Effective C++]条款03:尽可能使用const
- Effective C++--条款03:尽可能使用const
- Effective C++ 读书笔记 条款03:尽可能使用const
- Effective C++读书笔记 条款03:尽可能使用const
- 《Effective C++读书笔记》--条款03:尽可能使用const
- effective c++:条款21: 尽可能使用const
- 《Effective C++》学习笔记条款03 尽可能使用const
- effective C++读书笔记 条款三 尽可能使用const
- Effective C++——》条款3:尽可能使用const .
- Effective C++学习3 条款03:尽可能使用const
- Effective C++条款03解读:尽可能使用const
- effective c++ 条款21: 尽可能使用const
- effective c++条款21: 尽可能使用const
- 条款03:尽可能使用const
- 条款03:尽可能使用const
- cannot open include file 'afxres.h'错误的一种解决方法
- 20.[个人]C++线程入门到进阶(20)----线程函数:OpenThread
- C#实现闪动托盘图标效果的方法
- 140.Fragment实现程序锁未加锁模块
- 进制转换
- 读书笔记《Effective C++》条款03:尽可能使用const
- myeclipse的problem报错,工程出现了一个感叹号
- easyui datagrid combobox多选第一个时最前面会多加“,”逗号
- leetcode 13. Roman to Integer
- raw binary文件探秘
- webstrom注册方法 不用下载插件
- 试探用法
- 5.文件操作 --- 系统调用
- 【C语言】(windows.h)MessageBox函数