没有合适的资源?快使用搜索试试~ 我知道了~
effective C++
需积分: 3 126 下载量 95 浏览量
2009-08-20
06:47:58
上传
评论 2
收藏 703KB DOC 举报
温馨提示
试读
64页
effective C++ effective C++ effective C++ effective C++ effective C++
资源推荐
资源详情
资源评论
第一章 从 C 转向 C++.......................................................................................................................2
条款 1:尽量用 const 和 inline 而不用#define.........................................................................2
条款 2:尽量用<iostream>而不用<stdio.h>............................................................................5
条款 3:尽量用 new 和 delete 而不用 malloc 和 free...............................................................7
条款 4:尽量使用 c++风格的注释...........................................................................................8
第二章 内存管理................................................................................................................................9
条款 5:对应的 new 和 delete 要采用相同的形式................................................................10
条款 6:析构函数里对指针成员调用 delete.........................................................................11
条款 7:预先准备好内存不够的情况....................................................................................12
条款 8: 写 operator new 和 operator delete 时要遵循常规.....................................................19
条款 9: 避免隐藏标准形式的 new..........................................................................................23
条款 10: 如果写了 operator new 就要同时写 operator delete................................................25
第三章 构造函数,析构函数和赋值操作符.................................................................................32
条款 12: 尽量使用初始化而不要在构造函数里赋值...........................................................35
条款 13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同...........................40
条款 14: 确定基类有虚析构函数............................................................................................41
条款 15: 让 operator=返回*this 的引用...................................................................................46
条款 16: 在 operator=中对所有数据成员赋值.......................................................................49
条款 17: 在 operator=中检查给自己赋值的情况...................................................................53
第四章 类和函数:设计与声明.....................................................................................................58
条款 18: 争取使类的接口完整并且最小................................................................................60
条款 19: 分清成员函数,非成员函数和友元函数...............................................................63
条款 20: 避免 public 接口出现数据成员................................................................................68
条款 21: 尽可能使用 const.......................................................................................................70
条款 22: 尽量用“传引用”而不用“传值”..................................................................................77
条款 23: 必须返回一个对象时不要试图返回一个引用......................................................80
条款 24: 在函数重载和设定参数缺省值间慎重选择...........................................................84
条款 25: 避免对指针和数字类型重载....................................................................................88
条款 26: 当心潜在的二义性....................................................................................................91
条款 27: 如果不想使用隐式生成的函数就要显式地禁止它...............................................94
条款 28: 划分全局名字空间....................................................................................................95
第五章 类和函数: 实现.................................................................................................................100
条款 29: 避免返回内部数据的句柄......................................................................................101
条款 30: 避免这样的成员函数:其返回值是指向成员的非 const 指针或引用,但成员的
访问级比这个函数要低.........................................................................................................106
条款 31: 千万不要返回局部对象的引用,也不要返回函数内部用 new 初始化的指针的
引用.........................................................................................................................................108
条款 32: 尽可能地推迟变量的定义......................................................................................111
条款 33: 明智地使用内联......................................................................................................114
条款 34: 将文件间的编译依赖性降至最低..........................................................................119
第六章 继承和面向对象设计........................................................................................................127
条款 35: 使公有继承体现 "是一个" 的含义........................................................................128
条款 36: 区分接口继承和实现继承......................................................................................134
条款 37: 决不要重新定义继承而来的非虚函数.................................................................142
条款 38: 决不要重新定义继承而来的缺省参数值.............................................................144
条款 39: 避免 "向下转换" 继承层次....................................................................................146
条款 40: 通过分层来体现 "有一个" 或 "用...来实现"........................................................154
条款 41: 区分继承和模板......................................................................................................157
条款 42: 明智地使用私有继承..............................................................................................161
条款 43: 明智地使用多继承..................................................................................................166
条款 44: 说你想说的;理解你所说的..................................................................................181
第七章 杂项....................................................................................................................................182
条款 45: 弄清 C++在幕后为你所写、所调用的函数.........................................................182
条款 46: 宁可编译和链接时出错,也不要运行时出错.....................................................186
条款 47: 确保非局部静态对象在使用前被初始化.............................................................189
条款 48: 重视编译器警告......................................................................................................190
条款 49: 熟悉标准库..............................................................................................................190
条款 50: 提高对 C++的认识..................................................................................................196
第一章 从 C 转向 C++
对每个人来说,习惯 需要一些时间,对于已经熟悉 的程序员来说,这
个过程尤其令人苦恼。因为 是 的子集,所有的 的技术都可以继续使
用,但很多用起来又不太合适。例如,程序员会认为指针的指针看起来很
古怪,他们会问:为什么不用指针的引用来代替呢?
是一种简单的语言。它真正提供的只有有宏、指针、结构、数组和函数。不
管什么问题, 都靠宏、指针、结构、数组和函数来解决。而 不是这样。
宏、指针、结构、数组和函数当然还存在,此外还有私有和保护型成员、函数
重载、缺省参数、构造和析构函数、自定义操作符、内联函数、引用、友元、
模板、异常、名字空间,等等。用 比用 具有更宽广的空间,因为设计
时有更多的选择可以考虑。
在面对这么多的选择时,许多 程序员墨守成规,坚持他们的老习惯。一般来
说,这也不是什么很大的罪过。但某些 的习惯有悖于 的精神本质,他
们都在下面的条款进行了阐述。
条款 1:尽量用 const 和 inline 而不用#dene
这个条款最好称为:“尽量用编译器而不用预处理”,因为#define 经常被认为好
象不是语言本身的一部分。这是问题之一。再看下面的语句:
编译器会永远也看不到 ASPECT_RATIO 这个符号名,因为在源码进入编译器之
前,它会被预处理程序去掉,于是 ASPECT_RATIO 不会加入到符号列表中。如
果涉及到这个常量的代码在编译时报错,就会很令人费解,因为报错信息指的
是 1.653,而不是 ASPECT_RATIO。如果 ASPECT_RATIO 不是在你自己写的头
文件中定义的,你就会奇怪 1.653 是从哪里来的,甚至会花时间跟踪下去。这
个问题也会出现在符号调试器中,因为同样地,你所写的符号名不会出现在符
号列表中。
解决这个问题的方案很简单:不用预处理宏,定义一个常量:
这种方法很有效。但有两个特殊情况要注意。
首先,定义指针常量时会有点不同。因为常量定义一般是放在头文件中(许多
源文件会包含它),除了指针所指的类型要定义成 const 外,重要的是指针也经
常要定义成 const。例如,要在头文件中定义一个基于 char*的字符串常量,你
要写两次 const:
!"#! "$!%&'("&
关于 const 的含义和用法,特别是和指针相关联的问题,参见条款
21 。
另外,定义某个类)!*的常量一般也很方便,只有一点点不同。要把常量限
制在类中,首先要使它成为类的成员;为了保证常量最多只有一份拷贝,还要
把它定义为静态成员:
+++
!,!%!("-
."/0!1
!//$2'2$33!!"!/
/"4$2'2$5 336!
7
还有一点,正如你看到的,上面的语句是 NUM_TURNS 的声明,而不是定义,
所以你还必须在类的实现代码文件中定义类的静态成员:
/,!%!("11$2'2$ 33%!!"(//
338/!/%.
你不必过于担心这种小事。如果你忘了定义,链接器会提醒你。
旧一点的编译器会不接受这种语法,因为它认为类的静态成员在声明时定义初
始值是非法的;而且,类内只允许初始化整数类型)如:/99 !"等*,
还只能是常量。
在上面的语法不能使用的情况下,可以在定义时赋初值:
!8/"/8!-33 /8/ !
."/0!1 33 !"
!/:2;,:
7
33 /8/ !/%.%!/
8/"/8!11:2;,:
大多数情况下你只要做这么多。唯一例外的是当你的类在编译时需要用到这个
类的常量的情况,例如上面 ,!%!("11" 数组的声明)编译过程中编
译器一定要知道数组的大小*。所以,为了弥补那些)不正确地*禁止类内进行整
型类常量初始化的编译器的不足,可以采用称之为“借用 %<的方法来解决。
这种技术很好地利用了当需要 / 类型时可以使用枚举类型的原则,所以
,!%!(" 也可以象这样来定义:
!,!%!("-
."/0!1
%-$2'2$7 33& % !=&>%!=
33$2'2$!(%/!%
336"
/"4$2'2$533
7
除非你正在用老的编译器)即写于 ?? 年之前*,你不必借用 %。当然,
知道有这种方法还是值得的,因为这种可以追溯到很久以前的时代的代码可是
不常见的哟。
回到预处理的话题上来。另一个普遍的 指令的用法是用它来实现那些
看起来象函数而又不会导致函数调用的宏。典型的例子是计算两个对象的最大
值:
%!@)!9*))!*A)*B)!*1)**
这个语句有很多缺陷,光想想都让人头疼,甚至比在高峰时间到高速公路去开
车还让人痛苦。
无论什么时候你写了象这样的宏,你必须记住在写宏体时对每个参数都要加上
括号;否则,别人调用你的宏时如果用了表达式就会造成很大的麻烦。但是即
使你象这样做了,还会有象下面这样奇怪的事发生:
/!9C
%!@)!9*33!的值增加了 D 次
%!@)!9C*33!的值只增加了 次
这种情况下,%!@ 内部发生些什么取决于它比较的是什么值!
幸运的是你不必再忍受这样愚笨的语句了。你可以用普通函数实现宏的效率,
再加上可预计的行为和类型安全,这就是内联函数)见条款
*:
///%!@)/!9/*-""!AB!17
不过这和上面的宏不大一样,因为这个版本的 %!@ 只能处理 / 类型。但模板
可以很轻巧地解决这个问题:
%.!E!A
//F%!@)F!9F*
-""!AB!17
这个模板产生了一整套函数,每个函数拿两个可以转换成同种类型的对象进行
比较然后返回较大的)常量*对象的引用。因为不知道 的类型,返回时传递引
用可以提高效率)见条款
DD *。
顺便说一句,在你打算用模板写象 %!@ 这样有用的通用函数时,先检查一下标
准库)见条款
G? *,看看他们是不是已经存在。比如说上面说的 %!@,你会惊
喜地发现你可以后人乘凉:%!@ 是 标准库的一部分。
有了 和 //,你对预处理的需要减少了,但也不能完全没有它。抛弃
/ 的日子还很远,/663/66 在控制编译的过程中还扮演重要角
色。预处理还不能退休,但你一定要计划给它经常放长假。
条款 2:尽量用<iostream>而不用<stdio.h>
是的,!6 和 ."/6 很轻巧,很高效,你也早就知道怎么用它们,这我承认。
但尽管他们很有用,事实上 !6 和 ."/6 及其系列还可以做些改进。尤其是,
他们不是类型安全的,而且没有扩展性。因为类型安全和扩展性是 的基石,
所以你也要服从这一点。另外,!63."/6 系列函数把要读写的变量和控制
读写格式的信息分开来,就象古老的 :$ 那样。是该向五十年代说诀别
的时候了!
不必惊奇,!63."/6 的这些弱点正是操作符AA和EE的强项1
//
!/!"33"是个有理数
/AA/AA"
EE/EE"
上面的代码要通过编译,AA和EE必须是可以处理 !/! 类型对象的重载
函数)可能要通过隐式类型转换*。如果没有实现这样的函数,就会出错)处理
/ 不用这样做,因为它是标准用法*。另外,编译器自己可以根据不同的变量
类型选择操作符的不同形式,所以不必劳你去指定第一个要读写的对象是 /
而第二个是 !/!。
剩余63页未读,继续阅读
资源评论
tianyuxia
- 粉丝: 0
- 资源: 2
上传资源 快速赚钱
- 我的内容管理 展开
- 我的资源 快来上传第一个资源
- 我的收益 登录查看自己的收益
- 我的积分 登录查看自己的积分
- 我的C币 登录后查看C币余额
- 我的收藏
- 我的下载
- 下载帮助
安全验证
文档复制为VIP权益,开通VIP直接复制
信息提交成功