条款1:尽量用const和inline而不用#define
编译器会永远也看不到符号名
条款2:尽量用iostream而不用stdio.h
条款3:尽量用new和delete而不用malloc和free
条款4:尽量使用c++风格的注释
c++不推荐c语言式的/* */,使用///
条款5:对应的new和delete要采用相同的形式
如果你调用new时用了[],调用delete时也要用[]。如果调用new时没有用[],那调用delete时也不要用[]
条款6:析构函数里对指针成员调用delete
条款7:预先准备好内存不够的情况
#include 里面的:std::set_new_handler(no_memory);
条款8: 写operator new和operator delete时要遵循常规
条款9: 避免隐藏标准形式的new
1.在类里写一个支持标准new调用方式的operator new,它和标准new做同样的事。static void * operator new(size_t size){ return ::operator new(size); }2.或为每一个增加到operator new的参数提供缺省值
条款10: 如果写了operator new就要同时写operator delete
为了效率
条款11:为需要动态分配内存的类声明一个拷贝构造函数和一个赋值操作符
只要类里有指针时,就要写自己版本的拷贝构造函数和赋值操作符函数。
条款12: 尽量使用初始化而不要在构造函数里赋值
1.有些情况下必须用初始化,特别是const和引用数据成员只能用初始化,不能被赋值。
2.当使用成员初始化列表时,只有一个成员函数被调用。而在构造函数里赋值时,将有两个被调用。
3.但有一种情况下,对类的数据成员用赋值比用初始化更合理。这就是当有大量的固定类型的数据成员要在每个构造函数里以相同的方式初始化的时候。
条款13: 初始化列表中成员列出的顺序和它们在类中声明的顺序相同
使用继承时,要把基类的初始化列在成员初始化列表的最前面。
条款14: 确定基类有虚析构函数
虚函数的目的是让派生类去定制自己的行为,所以几乎所有的基类都包含虚函数。
在想要成为抽象类的类里声明一个纯虚析构函数。
条款15: 让operator=返回*this的引用
当定义自己的赋值运算符时,必须返回赋值运算符左边参数的引用,*this。
条款16: 在operator=中对所有数据成员赋值
条款17: 在operator=中检查给自己赋值的情况
不需要为自己赋值,保证正确性和效率。
所以任何时候写一个函数,只要别名有可能出现,就必须在写代码时进行处理。
c& c::operator=(const c& rhs)
{
// 检查对自己赋值的情况
if (this == &rhs) return *this;
…
}
条款18: 争取使类的接口完整并且最小
友元函数在所有实际应用中都是类的接口的一部分。这意味着友元函数影响着类的接口的完整性和最小性。
条款19: 分清成员函数,非成员函数和友元函数
1.虚拟函数必定是某个类的成员函数。能避免使用友元函数就要避免。
2.operator>>和operator<<决不能是成员函数。如果函数需要对最左边的参数进行类型转换,让函数为非成员函数。如果函数还需要访问相关类的非公有成员,让函数成为相关类的友元函数。
3.其它情况都声明为成员函数。
条款20: 避免public接口出现数据成员
条款21: 尽可能使用const
指针里你可以在头脑里画一条垂直线穿过指针声明中的星号(*)位置,如果const出现在线的左边,指针指向的数据为常量;如果const出现在线的右边,指针本身为常量;如果const在线的两边都出现,二者都是常量。
条款22: 尽量用“传引用”而不用“传值”
“通过值来传递一个对象”的具体含义是由这个对象的类的拷贝构造函数定义的。如果是一个很小的对象(小于指针的)——例如int——传值实际上会比传引用更高效。
条款23: 必须返回一个对象时不要试图返回一个引用
选择可以完成正确功能的那个
条款24: 在函数重载和设定参数缺省值间慎重选择
头文件中,numeric_limits::min()返回的是代表整数类型的最小值。
条款25: 避免对指针和数字类型重载
0的二义性,成员函数模板
条款26: 当心潜在的二义性
条款27: 如果不想使用隐式生成的函数就要显式地禁止它
显式地声明一个成员函数,就防止了编译器去自动生成它的版本;使函数为private,就防止了别人去调用它。成员函数和友元函数还是可以调用私有函数,除非不去定义(实现)这个函数。
条款28: 划分全局名字空间
struct是namespace的很好的近似,它在很多方面很欠缺,其中很明显的一点是对运算符的处理。
条款29: 避免返回内部数据的句柄
例如指针
条款30: 避免这样的成员函数:其返回值是指向成员的非const指针或引用,但成员的访问级比这个函数要低
public private protected
条款31: 千万不要返回局部对象的引用,也不要返回函数内部用new初始化的指针的引用
条款32: 尽可能地推迟变量的定义
条款33: 明智地使用内联
条款34: 将文件间的编译依赖性降至最低
1.如果可以使用对象的引用和指针,就要避免使用对象本身.尽可能使用类的声明,而不使用类的定义.
2.协议类没有实现,一般没有数据成员,没有构造函数;有一个虚析构函数,还有一套纯虚函数,用于制定接口.
条款35: 使公有继承体现 “是一个” 的含义
条款36: 区分接口继承和实现继承
定义纯虚函数的目的在于,使派生类仅仅只是继承函数的接口。
声明简单虚函数的目的在于,使派生类继承函数的接口和缺省实现。
声明非虚函数的目的在于,使派生类继承函数的接口和强制性实现。
条款37: 决不要重新定义继承而来的非虚函数
条款38: 决不要重新定义继承而来的缺省参数值
条款39: 避免 “向下转换” 继承层次
转换用虚函数调用来代替,使这些类的每个虚函数成为一个空操作。第二个方法是加强类型约束。
条款40: 通过分层来体现 “有一个” 或 “用…来实现”
条款41: 区分继承和模板
当对象的类型不影响类中函数的行为时,就要使用模板来生成这样一组类。
当对象的类型影响类中函数的行为时,就要使用继承来得到这样一组类。
条款42: 明智地使用私有继承
私有继承意味着 “用…来实现”。私有继承意味着只是继承实现,接口会被忽略。
条款43: 明智地使用多继承
两个类具有共同点的方式不是让一个类从另一个类继承,而是让它们都从一个共同的基类继承
条款44: 说你想说的;理解你所说的
条款45: 弄清C++在幕后为你所写、所调用的函数
1.如果想让一个包含引用成员的类支持赋值,你就得自己定义赋值运算符。
2.
class Empty{};
等价于:
class Empty {
public:
Empty(); // 缺省构造函数
Empty(const Empty& rhs); // 拷贝构造函数
~Empty(); // 析构函数 —- 是否
// 为虚函数看下文说明
Empty&
operator=(const Empty& rhs); // 赋值运算符
Empty* operator&(); // 取址运算符
const Empty* operator&() const;
};
条款46: 宁可编译和链接时出错,也不要运行时出错
条款47: 确保非局部静态对象在使用前被初始化
条款48: 重视编译器警告
条款49: 熟悉标准库
string.h是旧的C头文件,对应的是基于char*的字符串处理函数;string是包装了std的C++头文件,对应的是新的string类(看下文);cstring是对应于旧C头文件的std版本
条款50: 提高对C++的认识
为什么隐式生成的拷贝构造函数和赋值运算符要象现在这样工作呢,尤其是指针(参见条款11和45)?
因为这是C对struct进行拷贝和赋值的方式,和C兼容很重要。
为什么析构函数不自动被声明为virtual(参见条款14),为什么实现细节必须出现在类的定义中(参见条款34)呢?
因为不这样做就会带来性能上的损失,效率很重要。
为什么C++不能检测非局部静态对象之间的初始化依赖关系(参见条款47)呢?
因为C++支持单独编译(即,分开编译源模块,然后将多个目标文件链接起来,形成可执行程序),依赖现有的链接器,不和程序数据库打交道。所以,C++编译器几乎不可能知道整个程序的一切情况。
为什么C++不让程序员从一些繁杂事务如内存管理(参见条款5-10)和低级指针操作中解脱出来呢?
因为一些程序员需要这些处理能力,一个真正的程序员的需要至关重要。