Effective C中文版第三版 高清PDF总结.doc
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_1.gif)
![资源得分’ title=](/images/score_05.gif)
《Effective C中文版第三版 高清PDF总结.doc》由会员分享,可在线阅读,更多相关《Effective C中文版第三版 高清PDF总结.doc(186页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、Effective C+阅读笔记Effective C+阅读笔记1原则3:尽可能使用const4原则5:了解C+默默编写并调用哪些函数6原则6:若不想使用编译器自动生成的函数,就应该明确拒绝8原则7:为多态基类声明virtual析构函数11原则8:别让异常逃离析构函数15原则9:绝不在构造和析构过程中调用virtual函数16原则10:令operator=返回一个reference to *this19原则11:在operator=中处理“自我赋值”19原则12:复制对象时勿忘其每一个成分21原则13:以对象管理资源22原则14:在资源管理类中小心COPYING行为24原则15:在资源管理类中
2、提供对原始资源的访问25原则16:成对使用new和delete时要采用相同形式27原则17:以独立语句将newed对象置入智能指针28原则18:让接口容易被正确使用,不易被误用29原则19:设计class犹如设计type30原则20:宁以引用传递代替值传递31原则21:必须返回对象时,别妄想返回其引用32原则22:将成员变量声明为private33原则23:宁以非member、非friend替换member函数34原则24:若所有参数皆需要类型转换,请为此采用非member函数35原则25:考虑写出一个不抛出异常的swap函数37原则26:尽可能延后变量定义式的出现时间39原则27:尽量少做类
3、型转换动作40原则28:避免返回handles指向对象的内部成分43原则29:为“异常安全”而努力是值得的45原则30:透彻了解inline(内联)的里里外外48原则31:将文件间的变异依存关系降至最低50原则32:确定你的public继承塑造出了IS-A关系53条款33:避免屏蔽继承而来的名字54原则34:区分接口继承和实现继承55原则35:考虑virtual函数以外的其他选择57原则36:决不能重新定义继承而来的非virtual函数60原则37:绝不重新定义继承而来的缺省参数值62原则38:通过复合塑造出HAS-A关系或者根据某物实现出来63原则39:明知而审慎地使用PRIVATE继承64
4、原则40:明智而审慎地使用多重继承69原则41:了解隐式接口和编译期多态71原则42:了解typename的双重意义72原则43:学习处理模版化基类内的名称74原则44:将与参数无关的代码抽离templates76原则45:运用成员函数模版接受所有兼容类型78原则46:需要类型转换时请为模版定义非成员函数80原则47:请使用traits classes表现类型信息82原则48:认识template元编程85原则49:了解new-handler的行为87原则50:了解new和delete的合理替换时机90条款51:编写new和delete时需固守常规92原则52:写了placement new也
5、要写placement delete94原则54:不要忽视编译器的警告95原则54:让自己熟悉包括TR1在内的标准程序库96原则55:让自己熟悉Boost97本来是写在百度空间的,但是不知道咋回事百度博客中图片看不到了,所以百度博客的不稳定性可见一斑。于是我决定将我的领会和感受写在自己的云盘里面。虽好也弄个目录啥的,最后再整车成PDF格式的。这个标准我就参考我研究生期间论文的格式吧。原则3:尽可能使用constEffective C+里面第3条原则是尽量使用const。其原因是防止无意中更改而本来不应该更改的变量。本条款也提到const成员函数的重要性,原因之一就是只有const函数才能用来操
6、纵const对象。而所谓const对象就像下图所示的这样:有的时候会遇到在const函数中更改非const成员变量的情况,这个时候就要用到mutable关键字了。如果一个成员变量被mutable修饰,那么它在const函数中仍然可以被修改,但是前提是该成员变量是非const成员。还有一种情况就是为了防止代码重复,比如两个函数实现了同样的功能只是类型不同而已,这样就会导致两段几乎相同的代码段,这无疑会增加编译时间、维护和代码膨胀等风险。在本原则的有关叙述中,作者采用了强制类型转换来解决之,虽然作者本身在大多数情况下并不提倡做法。为了给用户一个一目了然的接口,一看就知道那些成员函数可以操纵cons
7、t对象而哪些不能,作者建议在类中明确将那些不改变对象的成员函数声明为const函数,虽然const成员函数可以使用非const成员变量,但是遵守这一原则会给客户带来极大的便利。因为const成员函数不更改对象,这就防止了由于误操作而带来的问题,因为最好用非const成员函数去调用const的实现,说白了就是直接return这个const成员函数,只不过需要对作为这个return的表达式的const成员函数进行一下强制类型转换使其成为非const型的。所以,在这里不得不提一下纯粹的C+的强制类型转换。关键在static_cast(value)是纯粹的C+强制类型转换的关键词和用法,它的使用频率是
8、最高的。const_cast(value)是用来消除const属性时用的。不过它不能用于基本类型。reinterpret_cast(value)它用于无关类型之间的转换。dynamic_cast(value)用于父子类指针之间的转换。在C+语言中只有这4中强制类型转换。原则5:了解C+默默编写并调用哪些函数这一篇博客是Effective C+中第5个条款。但现在感觉我还没太理解它到底说了什么,所以想写写博客,万一写着写着就明白了呢。首先在这里叙述一个机制,那就是空类,在默认的情况下,编译器会给它自动生成默认的构造函数、拷贝构造函数、拷贝赋值操作符=和析构函数。并且他们都是public的和inl
9、ine的。它与下面这个类是一样的。至于这些成员函数和操作符是干啥用的,我在前边的博文中阐述过了。其中,默认的构造函数负责调用父类和非static的构造函数和析构函数。如上图可见编译器自动生成的析构函数是非virtual的,如果父类中本身存在virtual的析构函数,编译器就不会自动产生非virtual的析构函数了。而默认的copy构造函数和copy赋值操作符只是copy非static成员到目标对象。不过,如果你手动写了它们中的一些,编译器就只会自动生成你没写的。比如你只写了构造函数,那么其他的东西编译器负责给你自动生成。至于说copy构造函数和copy赋值操作符的用法我以前的博文有提到过。而c
10、opy构造函数总是层层调用底层的copy构造函数来进行赋值,比如说copy构造函数要copy一个string类型的变量,那么它就会调用string的copy构造函数,实在没办法了,它再自己进行赋值操作。其实本原则着重讨论的是在什么情况下编译器不会自动生成这些东东。对于默认的构造函数而言,当你手动写了一个构造函数的话,编译器就不会再费那个劲了。而对于copy赋值操作符呢也是有自动生成条件的,那就是这个copy赋值操作符确实有存在的意义,并且它能在使用场合能正确工作,否则除非你自己手动写一个,要不然编译器是不会给你生成这些东东的。而在书中作者举了2个例子1个是引用,另一个是const常量,这两者所
11、指的对象都是不能更改的,那你非要给它们赋值,那肯定会导致copy赋值操作符的失败。书中还举个1个例子,一般情况下父类中如果有copy赋值操作符,在子类中编译器是不会再给自动生成copy赋值操作符,直接使用父类的就好了,因为编译器认为子类的copy赋值操作符是要能够处理父类的赋值操作的。所以如果你此时把父类的copy赋值操作符设置为private的,那么你就没有copy赋值操作符可用了,除非你自己在子类中写一个。原则6:若不想使用编译器自动生成的函数,就应该明确拒绝这是Effective C+中第6个原则,在某些情况下你不想让某些类的对象被拷贝,那么在这种情况下即使你不写copy构造函数和cop
12、y赋值操作符编译器也会为你生成,那么你不得不自己写它们俩。而你又不希望别人调用它们,所以这时你要将它们声明为private类型。一旦你写了,编译器就不会自动调用父类的copy构造函数和copy赋值操作符。即便这样本类内部成员函数和友元函数还是可以调用它们,该如何是好?办法就是你只声明这些函数而不去实现,没有实现就自然没有功能了,而既然实际上没用,你甚至连形参都可以省略,只在形参列表中写个形参类型即可,就像下图类的定义所示的这样:其中的几个函数实现如下所示:从上图可见,copy构造函数和copy赋值操作符都没有实现。在主程序中是如下调用的:运行结果如下所示:出现了错误提示,说copy构造函数无法
13、解析。现在我把copy构造函数和copy赋值操作符都注释掉。在运行得如下结果:而本思想只在阐述如果你不想让编译器为你自动生成函数,你就要自己手写。原则7:为多态基类声明virtual析构函数这是Effective C+中第7条原则,其内容是在具有多态用途的父类中应该使用virtual析构函数。首先要知道啥是多态。我就好说直白的,显得没有深度的东西。多态的一种体现就是通过父类的指针指向不同的子类来实现不同的功能,从而达到接口重用的目的。在这种情况下用作多态的父类往往具有至少一个virtual成员函数留给子类来实现。好了,现在铺垫完毕了,来说正题,为啥要有一个virtual析构函数呢?那是因为如果
14、没有这样一个virtual析构函数的话,子类的析构函数就不会被调用,那么对象的子类部分不会被析构,那么就会造成资源的泄露。现在来看下面的例子:derived继承了base,并且base中并没有virtual析构函数,那么调用过程如下所示:运行结果如下所示:从这个结果可以看到父类的析构函数执行了,说明对象的父类部分所占资源已经被释放,但是子类的析构函数并未调用这说明对象中子类部分所占资源并未得到释放。但是如果在父类中加上一个virtual析构函数的话就不一样了。同样的调用过程,运行结果如下所示:这说明对象的子类部分所占资源也被释放掉了。在这里再说点别的,一般来讲作为要被继承的父类的类中至少含有一
15、个virtual的成员函数留给子类去实现。而如果某类中一个virtual成员函数都没有的话,在很大程度上说明了该类不会被作为父类而存在,在这种情况下不应该把其析构函数设为virtual的。为啥呢?这与C+中virtual本身的实现机制有关,因为这样的类的对象必须要携带一个表,这个表叫vtbl,所以本来没必要多带这么个表,但是你非要多出一个来占个空间,这就是占个茅坑不拉屎的表现啊。所以不准备被继承的类是没有必要设置virtual析构函数的。在这里在介绍一种情况,当你希望在virtual类中把析构函数设为virtual的时候,应该吧析构函数设为纯virtual函数,并且给与空的实现,如下图所示:为
16、啥要这样做呢?因为析构函数调用顺序是从没有子类的子类那里的析构函数逐层调用父类的析构函数,所以如果这个纯virtual函数没有实现的话,编译器就会报错。这个原则简而言之就是,只有作为多态用途的父类才有必要使用virtual析构函数,其他的就是画蛇添足。另外,处于继承机制的类对象包含了它所能涉及到的最低层次及其以上的所有层次的成分。原则8:别让异常逃离析构函数这是Effective C+的第八条原则。主要说的是程序出现的异常不要从析构函数这里漏掉,也就是说析构函数应该承担起拦截异常的责任才行。如果异常越过了析构函数这一关,流窜到其他地方去,那么就会造成程序提早结束或者未知的风险,这个后果就很严重
17、了。对付这种情况通常有两种简单粗暴的手段:1、在析构函数内发现异常,立刻捕捉到并且结束整个程序;2、在析构函数中发现异常,立刻捕捉到并将其扼杀,掩人耳目,继续执行程序。其中第一种手段比第二种手段要好,这是为啥呢?因为方法1直接结束程序,其结果是可预料的,不会造成太大破坏。而方法2你这个异常是终止了,但是程序中其他部分与这个功能相关的势必会造成影响,也许还会因此带来其他异常的连锁反应,这个就不好办了。不过以上这两种方法都没能去正面处理出现的异常,所以这两种方法都不提倡。书中给出的解决方案是,再创建一个类用来处理异常,在这个类中有一个成员函数专门用来处理原来的类中的异常。而这个成员函数是调用原类中
18、的异常处理来完成的,这实际上就是变相的让原类自己处理异常,这是第一道关卡。然后异常处理类的析构函数中也有一份处理异常的代码,这部分是异常处理类自己的,这是第二道关卡。这个就是双保险,如果说在第二道关卡仍然不能有效处理异常,那没办法了,只能强行关闭程序了。再总结一下本原则就是无论如何也不能让异常突破析构函数这一关。原则9:绝不在构造和析构过程中调用virtual函数这是Effective C+中的第9条原则。简单的来说,如果你在父类的构造函数中调用了虚拟函数,那么子类的成员就会始终处于未初始化的状态,这样对象的子类成分就会出现不可预知的行为,这是非常危险的。那么这是为什么呢?在继承体系当中,你声
19、明了一个子类对象,那么这个子类对象其实是很复杂的,它包含了子类所有父类的成分。而这些成分是要一层一层的进行初始化的,其顺序是按照类的继承层次从上而下进行的,即从最远的那个父类到最近的那个父类,然后是本类的初始化。而C+的机制又是只有在父类成分初始化完毕以后才去处理子类成分的初始化工作,换句话说,如果父类的成分没有初始化完毕,它压根就不会去管子类的初始化工作。因为你在父类的构造函数中调用了虚拟函数,而这个虚拟函数一般在父类中是不进行实现的。鄙人以为,一个函数之所以被调用肯定是因为这个函数是有一定的功能实现的,要不你调用它干吗?我想C+的构造函数也是这么想的。但是,你现在非要在本来用于初始化的构造
20、函数中去调用一个没法初始化virtual函数,C+就认为这个对象的父类成分还没有初始化完毕,现在不能去初始化子类成分。所以,即使你现在声明了一个子类对象,子类中的成分还是没有得到初始化,所以就会出现不可预知的后果。C+对未定位的成员变量是采取无视的态度的,因为还没轮到你,你给我一边凉快去。在构造函数期间无视,在析构函数期间也是无视。而析构的顺序又是先子类再父类,因为对象的子类成分被无视,只有父类成分被析构,所以那些未定义的成员变量自始至终都是未定义的,你也不知道它们最终会怎样。为了证实这一点请看下面的例子:运行结果是这样的:看到这个结果,我不得不说现在的编译器已经很智能了,它直接把它拦下来了。
21、在介绍与本原则有关的内容时,作者举了一个应用场景。那就是当类中有多个不同版本的构造函数,它们的共同的初始化代码都统一放到一个初始化成员函数里面了,并且这个初始化成员函数调用了一个virtual成员函数,并且这个virtual成员函数会有一定的实现代码。当你建立子类对象时却调用了错误的virtual成员函数。在此作者并没有详细地解释是为什么,但他给出了一种解决办法。那就是在子类的构造函数的初始化成员列表中调用父类的构造函数去初始化对象中父类的部分,当然了,这时父类中的那个virtual函数你要改成非virtual函数了。在这里作者使用了一个技巧,他不是在成员初始化列表直接把父类成分所需的东西直接
22、给它,而是通过一个辅助函数返回一个值给父类进行初始化,这样写比较方便也比较可读。而且,这个辅助函数的是一个static类型。static类型的成员函数是静态成员函数,它的类的对象实例化之前就已经被实例化,换句话说它跟类中其他的成员不发生关系。另外,子类对象的父类成分是在子类成分之前先被实例化,而在子类对象实例化的中间也就是父类成分正在实例化,还没轮到子类成分实例化之前,子类中的成员函数啥的是未定义的,也就工作不了。而此时static成员函数却能工作,这有助于对象中父类成分的实例化,所以把此辅助函数设置为static类型。原则10:令operator=返回一个reference to *this
23、原则11:在operator=中处理“自我赋值”在这篇博文里面我打算写两个Effective C+中的原则,因为第一个原则太短了。现在介绍第一个原则:条款10,此条款旨在说明在你自己编写的赋值操作符=一定要返回该左值的引用。具体来说就是返回*this。这很好解释,因为this是指向本对象的指针,那么*this就是该对象的本身实体了。而你现在返回的只不过是该实体的一个代表符号而已。现在一般的赋值操作符都采用这个原则,虽然不是强制的,但是大家都遵守。下面来对条款11做一些介绍。条款11的内容很简单,就是一定要妥善处理赋值操作符=的自我赋值问题,就是自己给自己赋值的情况。那么这又是为什么呢?因为在某
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Effective 中文版第三版 高清PDF总结 中文版 第三 PDF 总结
![提示](https://www.taowenge.com/images/bang_tan.gif)
限制150内