条款1 数据抽象
一个类型就是一组操作。当我们在一个领域识别一个对象时,首要考虑的问题是可以用这个对象来做什么,而不是这个对象是怎么实现的。C++中不存在针对抽象数据类型设计的公认方案,但抽象数据类型的设计一般遵循以下四个步骤:
- 给抽象数据类型命名。一个良好的抽象数据类型应该表示一种单一的并且有良好定义的概念,而且类型名字应该是显而易见的。
- 列出抽象数据类型支持的操作。避免简单的提供get/set操作。
- 为抽象数据类型设计接口。接口设计要易于正确使用,不易于错误使用。多站在接口用户的角度想想。
- 实现类型,但不要让实现影响接口。
条款2 多态
多态类型就是带有虚函数的类类型。多态对象就是一种具有多个类型的对象,多态基类就是为满足多态对象需要而设计的基类。对于多态对象,重要的是从基类继承接口而不是实现。基类提供契约允许对接口进行多态编程,而多态类则对基类实现表现出“健康的不知情”。基类的设计要考虑继承用户的需求,派生类可以很容易的推出基类的契约并将其实现,而基类则对派生类的实现全然不知。
条款3 设计模式
设计模式是职业C++程序员工具箱的重要组成部分,是对成功设计经验的一点一点积累起来的智慧的封装。设计模式有两个重要特性:- 他描述了经过验证的成功的设计技术,这些技术可以根据不同的上下文环境进行制定。
- 更重要的是,在提及某个设计模式时,不仅包括具体的设计技术,而且还包括应用此设计模式的原因和使用这种设计模式的结果。
设计模式是关于某项技术信息和经验的高效且无歧义的句柄,在设计和文档中小心并使用设计模式主要包括一下四个方面:
- 设计模式必须有一个无歧义的名字。
- 模式描述必须定义该模式所能解觉得问题。
- 模式描述必须记录该问题的解决方案。
- 模式描述要记录该模式应用于某个上下文后的结果。
条款4 STL
STL包含三大组件:容器,算法,迭代器。容器用于容纳和组织元素。算法用于执行操作。迭代器用于访问容器元素。STL优秀思想主要体现在容器和作用于容器上的算法不需要相互了解。STL迭代器相当于指针,它可以是预定义的指针,也可以是用户定义的类类型。STL容器是对数据结构的一种抽象,以类模板的方式实现。迭代器提供了一种容器和算法协同工作的机制。
条款5 引用是别名而非指针
引用和指针的区别:- 永远不存在一个空引用。
- 所有引用都要初始化。
- 一个引用永远指向用来初始化它的对象。
引用必须初始化的要求,意味着一个引用初始化时它指向的对象必须存在,因为引用只是已经存在的对象的别名。指向非常量的引用不能用字面值或者临时量来初始化,然而指向常量的变量却可以。
条款6 数组形参
定义数组形参,传入的只是指向首元素的指针,这种情况叫做退化。退化会导致数组边界被忽略。通常使用vector或者string来替代。其他的解决方法如下:- 引用形参。void foo(int (&array)[12])。这种方式要求实参必须是大小为12的数组。
- 用模板的方法让编译器来考虑数组的大小问题。
template<int n>
void foo(int (&array)[n])
- 将数组大小作为实参传给函数。
void foo(int array[], in size)
对于多维数组,也可以使用模板的方法来处理。
总之,在使用数组形参的时候,要格外的小心。
条款7 常量指针与指向常量的指针
T* pt = new T; // 指向T的指针const T* pct = pt; // 指向常量T类型的指针
T* const cpt = pt; // 常量指针指向T类型
下面两种写法是一样的:
const T* pct = pt;
T const* pct = pt;
区别主要在const和*的相对位置。const在*前,为指向常量的指针,const在*后,则为常量指针。下面两种写法也是一样的,都表示指向常量的常量指针:
const T* const cpct = pt; //
T const* const cpct = pt; //
通常,指向非常量的指针可以转化为指向常量的指针,反之则不可以。
条款8 指向指针的指针
C++中指向指针的指针在指针数组中比较常见。在作为函数参数时,虽然指向指针的指针是合法的,但在C++中通常使用指向指针的引用来代替指向指针的指针,通常这种方法更安全,更简便。要首选指向指针的引用作为参数。如下所示:void foo(const char** p, char c); // 指向指针的指针作为参数类型
void foo(const char*& p, char c); // 指向指针的引用作为参数类型
适用于指针的转换并不适用于多级指针,即指向指针的指针。多态中,指向基类指针的指针和指向继承类指针的指针是不一样的。同样的情况也出现在const存在的时候。将指向非常量指针的指针转化为指向常量指针的指针是非法的。
条款9 新式类型转换操作符
尽量使用新式类型转换操作符,而不去使用旧式类型转换操作符(如C中的类型转换)。新式类型转换操作符有四个:- const_cast操作符允许移除类型中的const和volatile属性,只影响类型修饰符。
- static_cast操作符常见于将基类的指针或者引用转换为派生类的指针或者引用,但无法改变类型修饰符。
- reinterpret_cast不管三七二十一,将旧的类型直接按照bits当作新的类型。
- dynamic_cast只用于多态类型转换,将基类的指针转换为派生类的指针,在转换的过程中有类型安全检查,同时有运行时的开销。
static_cast和reinterpert_cast的区别在于,static_cast会正确的执行地址操作,而reinterper_cast只是简单的把旧的类型看作新的类型。