如果你对const足够了解,只需记住以下结论即可:

  • 将某些东西声明为const可帮助编译器侦测出错误用法,const可被施加于任何作用于内的对象、函数参数、函数返回类型、成员函数本体。
  • 编译器强制实施bitwise constness,但你编写程序时应该使用概念上的常量性(logical constness)
  • 当const和non-const成员函数有实质等价的实现时,令non-const版本调用const版本可避免代码重复

关键字const允许你指定一个语义约束,即指定一个对象不被改动,编译器会强制实施这项约束。只要你确信某个对象不该被改变(赋值操作等),你就应该将他指定为const。

值得注意的是cosnt与指针的关系,需要记住的是如果const出现在星号左边,表示被指物是常量,出现在右边则指指针自身是常量,如果两边都有,则表示被指物和指针都是常量。

[cpp] view plain copy
  1. char greeting[] = "hello";
  2. const char* p = greeting;//常量对象,非常量指针
  3. char* const p = greering;//常量指针,非常量对象
  4. const char* const p = greeting;//常量指针,常量对象
  5. char const* p = greeting;//仍然是常量对象,非常量指针(注意char和const的位置)

const成员函数

将const用于成员函数有两个理由

  • 使class接口容易被理解,因为可以得知哪个函数可以改动对象类型,哪个不行
  • 使操作const对象成为可能

const成员函数可以处理取得(并经修饰而成的cosnt对象),即const成员函数可以返回一个const对象。

另外需要注意的是,如果函数的返回类型是个内置类型,那么改动函数返回值就不合法,返回值是const时也是如此。

bitwise(physical) constness和logical constness

bitwise constness是C++对常量性的定义,其含义是对象内的任意一个bit都不允许更改。所以const成员函数不可以更改对象内任何非static成员变量

但是某些情况引发了异议:一个更改了指针所指物的成员函数虽然不能算是const,但如果只有指针隶属于对象,那么称此函数为bitwise const不会引发编译器异议

[cpp] view plain copy
  1. class CTextBlock
  2. {
  3. public:
  4. char& operator[](std::size_t position) const//bitwise cosnt声明,此const表示该成员函数隐含的this指针为const
  5. {
  6. return pText[position];//该操作可能更改指针所指物,但并不会引发编译器异议
  7. }
  8. private:
  9. char* pText;
  10. };

针对这种情况引发了logical constness概念,即const成员函数可以在编译器侦测不出的情况下修改它所处理的对象内的某些bit

如果想在const成员函数内修改对象成员变量,则必须绕开bitwise constness,这种情况下可以使用mutable关键字,mutable释放掉非static成员变量的bitwise constness约束。即可以在const成员函数内改变对象成员变量。

[cpp] view plain copy
  1. class CTextBlock
  2. {
  3. public:
  4. std::size_t length() const;
  5. private:
  6. char* pText;
  7. mutable std::size_t textLength;//使用了mutable关键字
  8. mutable bool lengthIsValid;
  9. };
  10. std::size_t length() const
  11. {
  12. if(!lengthIsValid)
  13. {
  14. textLength = std::strlen(pText);//可以在const成员函数内随意改变mutable修饰的成员变量
  15. lengthIsValid = true;
  16. }
  17. return textLength;
  18. }

在const和non-const成员函数中避免重复

如果一个函数的const和non-const版本所做的工作相同,则可以在non-const版本中使用const版本函数来避免代码重复

[cpp] view plain copy
  1. class TextBlock
  2. {
  3. public:
  4. const char& operator[](std::size_t positon) const
  5. {
  6. return text[position];
  7. {
  8. char & operator[](std::size_t position)
  9. {
  10. return
  11. const_cast<char&>(
  12. static_cast<const TextBlock&>(*this)
  13. [position];
  14. );
  15. }
  16. };

const版本的函数可能有点难于理解,但他只进行了两次强制类型转换。一次类型转换是为了明确指出调用的是const operator[],因为必须使用static_cast将*this类型转型为const TextBlock&,第二次使用const_cast移除返回值的const属性,使其与函数声明一致。

反过来,在const函数中调用其non-const版本是不合法的,因为const函数承诺绝不改变其对象的逻辑状态。

ps: 命名的强制类型转换的知识

[cpp] view plain copy
  1. static_cast:
  2. 任何具有明确定义的类型转换,只要不包含底层const(即指所指对象是常量的const),都可以使用static_cast。
  3. 特别地,当我们把指针存放在void*中,并且使用static_cast将其强制转换回原来类型时,应该确保指针的值保持不变,也就是说,强制转换的结果将与
  4. 原始地址值相等。因此,必须确保转换后所得的类型就是指针所指的类型,否则,类型一旦不符,将产生未定义的后果。
  5. const_cast:
  6. 只能改变运算对象的底层const。需要注意的是,如果对象本身是个常量,使用const_cast会产生未定义的后果,除非你知道自己在做什么,否则不要乱用。
  7. 使用const_cast做除了改变表达式常量属性以外的转换都将引发编译器错误
  8. dynamic_cast:
  9. dynamic_cast用于将基类指针或引用安全地转换成派生类的指针或引用,使用形式如下
  10. dynamic_cast<type*>(e)
  11. dynamic_cast<type&>(e)
  12. dynamic_cast<type&&>(e)
  13. 其中type必须是一个类类型,并且通常情况下含有虚函数。第一种形式中,e必须是有效的指针,第二种形式中e必须是左值,第三种类型中e不能是左值。
  14. 上面所有形式中,e必须满足三个条件中的任意一个。e的类型是目标type的共有派生类、e的类型是目标type的共有基类或者e的类型就是目标type的类型。
  15. reinterpret_cast:
  16. 为运算对象的位模式提供较低层次上的重新编译,例如
  17. int *pi;
  18. char *pc = reinterpert_cast<char*>(pi);//把int解释为char指针

《Effective C++》读书笔记 条款03 尽可能使用const 使代码更加健壮的更多相关文章

  1. 《Effective C++》读书笔记 条款02 尽量以const,enum,inline替换#define

    Effective C++在此条款中总结出两个结论 1.对于单纯常量,最好以const对象或enum替换#define 2.对于形似函数的宏,最好改用inline函数替换#define 接下来我们进行 ...

  2. effective C++ 读书笔记 条款08

    条款08  别让异常逃离析构函数: 假设在析构函数其中发生了异常,程序可能会过早结束或者导致不明白行为(异常从析构函数传播出去) 看代码: #include <iostream> usin ...

  3. effective C++ 读书笔记 条款11

    条款11: 在operator= 中处理"自我赋值" 在实现operator=时考虑自我赋值是必要的就像 x=y .我们不知道变量x与y代表的值是否为同一个值(把x和y说成是一个指 ...

  4. Effective C++ -----条款03:尽可能使用const

    如果关键字const出现在星号左边,表示被指物是常量:如果出现在星号右边,表示指针自身是常量:如果出现在星号两边,表示被指物和指针两者都是常量. char greeting[] = " he ...

  5. effective C++ 读书笔记 条款14 以对象管理资源

    如果我们使用一个投资行为的程序库: #include "stdafx.h" #include <iostream> #include <memory> us ...

  6. 条款03 尽可能使用const

    一.概述 使用const约束对象:可以获得编译器的帮助(指出相关出错的地方) const与成员函数:const重载.转型.避免代码重复 二.细节 1. 为什么有些函数要返回const对象(看上去没必要 ...

  7. Effective STL 读书笔记

    Effective STL 读书笔记 标签(空格分隔): 未分类 慎重选择容器类型 标准STL序列容器: vector.string.deque和list(双向列表). 标准STL管理容器: set. ...

  8. Effective STL读书笔记

    Effective STL 读书笔记 本篇文字用于总结在阅读<Effective STL>时的笔记心得,只记录书上描写的,但自己尚未熟练掌握的知识点,不记录通用.常识类的知识点. STL按 ...

  9. 《Effective C++ 》学习笔记——条款03

    ***************************************转载请注明出处:http://blog.csdn.net/lttree************************** ...

随机推荐

  1. LeetCode22.括号生成 JavaScript

    给出 n 代表生成括号的对数,请你写出一个函数,使其能够生成所有可能的并且有效的括号组合. 例如,给出 n = 3,生成结果为: [ "((()))", "(()())& ...

  2. Swift_TableView(delegate,dataSource,prefetchDataSource 详解)

    Swift_TableView(delegate,dataSource,prefetchDataSource 详解) GitHub import UIKit let identifier = &quo ...

  3. 第四模块MySQL50题作业,以及由作业引申出来的一些高端玩法

    一.表关系 先参照如下表结构创建7张表格,并创建相关约束                 班级表:class       学生表:student       cid caption grade_id ...

  4. Linux awk命令用法

    概述 awk就是把文件逐行的读入,以空格为默认分隔符将每行切片,切开的部分再进行各种分析处理 awk工作流程是这样的:读入有'\n'换行符分割的一条记录,然后将记录按指定的域分隔符划分域,填充域,$0 ...

  5. 解决微信小程序安卓手机访问不到图片,无法显示图片

    关于微信小程序不显示图片 通病可能有以下几个可能性: 非本地图片:确定图片资源存在,copy 图片url再浏览器打开,确定图片资源存在且能正常访问 本地图片:确定相对路径或者绝对路径正确 微信小程序图 ...

  6. php源码建博客3--区分平台的MVC结构

    主要: 模型单例工厂 目录结构优化 区分平台(前台,后台....) --------------文件结构:-------------------------------------- blog├─Ap ...

  7. 解决thinkphp query()执行原生SQL语句成功结果报错的问题

    1.query方法 query方法用于执行SQL查询操作,如果数据非法或者查询错误则返回false,否则返回查询结果数据集(同select方法). 2.execute方法 execute用于更新和写入 ...

  8. 基于C语言的面向对象编程

    嵌入式软件开发中,虽然很多的开发工具已经支持C++的开发,但是因为有时考虑运行效率和编程习惯,还是有很多人喜欢用C来开发嵌入式软件.Miro Samek说:"我在开发现场发现,很多嵌入式软件 ...

  9. ruby 条件判断&循环控制

    参考:https://www.jb51.net/article/66709.htm

  10. C语言变量的初始化

    关于C语言变量是否需要初始化的问题.以前西北工业大学的C语言老师说的是,需要初始化,如果不初始化就使用的话,变量的值是以前遗留在内存中的,是不确定的(这只是针对局部变量的).C语言全局变量如果没有初始 ...