| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> <Effective C++>读书笔记 -> 正文阅读 |
|
[C++知识库]<Effective C++>读书笔记 |
条款02? 尽量以const,enum,inline替换#define?? ? ? ? 这个条款被作者认为改成"宁以编译器替代预处理器"更好,我们要先知道编译阶段和预处理阶段都干了什么 ?(1) 预处理 可以看出,在预处理的时候就进行宏替换,也就是将宏定义做文本替换,但由于预处理没有类型检查,所以经常会出现一些我们预期之外的错误的行为。 解决的办法是以一个常量替换上述的宏(#define),值得注意的是class专属常量,观察以下代码?
为了将常量的作用域限制于class内,必须让它成为class的一个成员;为此确保常量只有一份实体,所以必须让它成为一个static成员. 而你看到的是NumTurns的是声明而非定义,由于C++要求你对所使用的任何东西都提供一个定义,即在类外定义以下代码
但如果它是个class专属常量又是static且为整数类型(如int、bool、char等),允许在类内初始化且只能是常量。所以可以不需要以上的定义代码. 对于形似函数的宏,最好改用inline函数来替换#define 由于形似函数的宏没有类型检查,只在预处理阶段进行文本替换,会出现意想不到的可怕后果,使用template inline可以获得宏带来的效率以及一般函数的所有可预料行为和类型安全性. 谨记 1.对于单纯常量,最好以const对象或enums替换#define 2.对于形似函数的宏,最好改用inline函数来替换#define 条款03:尽可能使用const关键字const多才多艺,它可以修饰常量,文件,函数,区块作用域里被声明为static的对象 修饰指针的,无非就那几种,注意const与*的相对位置就ok啦,这里我不再赘述.比较陌生的还是为STL的迭代器加上const,该怎么加呢,我们首先要清楚迭代器的作用像T*指针,声明迭代器为const就像声明指针为const一样,具体表现有以下代码
令返回值为一个常量,往往会降低客户错误造成的意外,也不至于放弃安全性与高效性,比如
所以,将operator*的回传值声明为const可以预防那个"没意思的赋值动作",这就是返回值加上const的原因. Effective C++中指出,对成员函数加上const到底意味着什么? 有一种观念是不更改对象内的任何一个bit,另一种是不可以更改对象内任何non-static成员变量,考虑以下代码
我们可以看到return值为?char&的const成员函数,它的意思不会引发编译器异议,因为函数体内确实没有任何改动对象的语句,但是我如果这样来改动const对象呢 这样一来确实改动了const对象,因为编译器强制实施第二种观念,也就是不可以更改对象内任何non-static成员变量.但我们这里只是修改了对象的某些bits. 对于某些成员变量,若我们想要它总是可变的,即便在const对象里,可以在该成员变量前加上mutable. 最后提到的一点是,如果const与non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可以减少代码量,如以下代码
其中static_cast是为了给*this加上const(因为const成员函数的this指针是const *this),接着使用const_cast是为了移除返回类型的const. 而反向做法是不允许的(令const调用非const成员函数),我认为,non-const函数里可以写入const函数的内容,但const函数不能写入non-const函数的内容呀! 谨记 1.将某些东西声明为const可以帮助编译器侦测出错误用法,const可被施加于任何作用域内的对象,函数参数,函数返回类型,成员函数本体(不能作用在非成员函数本体) 2.便以及强制实施bitwise constness,但你编写程序时应该使用"概念上的常量性" 3.当const和non-const成员函数有着实质等价的实现时,令non-const版本调用const版本可避免代码重复 条款42:了解typename的双重意义我们在写类模板或函数模板时,typename与class的意义一样
然而C++并不总是把class与typename视为等价,我们来看看typename的另一种含义,假设我们有个template function,代码如下(这段代码不是有效的代码)
对于这个侯捷老师翻译的嵌套从属名称,我先来说说我理解的从属名称,我们声明一个变量 iter,它的类型是C::const_iterator,而这个类型是关于<typename C>的,也就是依赖与模板C,所以它称之为从属名称,嵌套呢?我认为,iter 是C类里的const_iterator类型,所以它就是一个嵌套名称.合起来就是嵌套从属名称 Effective C++ 书里指出:如果解析器在template中遭遇一个嵌套从属名称,它便假定这个名称不是个类型,除非你告诉它,否则默认为不是类型,那我们以解析器的角度来理解这段代码,解析器完全有可能认为const_iterator是C中的静态数据成员! 如果你这么写代码
?那么解析器可以将它理解为C类里的const_iterator变量与x相乘!这听起来有点荒唐,因为我们明知道C::const_iterator是个类型,x只是指向这类型的指针.解决之道是在嵌套从属名称前加上typename,相当于我们告诉C++说C::const_interator是一个类型. typename只被用来验明嵌套从属类型名称;其他名称不该有它的存在,而且有两个例外,不能放在嵌套从属名称之前(1) typename不可以出现在base classes list内的嵌套从属名称之前 (2) 也不可以在member initialzation list中作为base class修饰符
在这里做出我的理解:? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(1) 基类列表一定是类型名,不需要再告诉编辑器? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?(2)?初始化列表一定是成员变量名,不可以加上typename 谨记:? 1.声明template参数时,前缀关键字class和typename可互换 2.使用关键字typename标识嵌套从属名称;但不得在base class lists(基类列) 或member initialization list ( 成员初值列 ) 内以它作为base class修饰符 注 : 一部分摘自该文章?C++ 基础概念、语法和易错点整理_Tyler_Zx的博客-CSDN博客 |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 | -2024/11/24 4:28:36- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |