有人说C++程序员可以分为两类,读过Effective C++的和没读过的。世界顶级C++大师Scott Meyers 成名之作的第三版的确当得起这样的评价。
本书并没有你告诉什么是C++语言,怎样使用C++语言,而是从一个经验丰富的C++大师的角度告诉程序员:怎么样快速编写健壮的,高效的,稳定的,易于移植和易于重用的C++程序。
本笔记共有55个条款,从多个角度介绍了C++的使用经验和应遵循的编程原则,每天都会更新。
条款01: 视C++ 为一个语言联邦
本条款提示读者,C++已经不是一门很单一的语言,而应该将之视为一个由相关语言组成的联邦。从语言形式上看,它是一个多重范型编程语言(multiparadigm programminglanguage) ,一个同时支持过程形式(procedural)、面向对象形式(object-oriented)、函数形式(functional) 、泛型形式(generic) 、元编程形式(metaprogramming )的语言,这些能力和弹性使c++成为一个无可匹敌的工具。为了理解c++,你必须认识其主要的次语言,幸运的是总共只有下面四个。从语言种类上看,它由若干次语言组成,分别为:
(1) C。说到底C++ 仍是以C 为基础。区块(blocks) 、语句( statements) 、预处理器( preprocessor) 、内置数据类型(built-in data types) 、数组(arrays) 、指针(pointers) 等统统来自C。
(2) Object-Oriented C++。这部分也就是C with Classes 的: classes (包括构造函数和析构函数) ,封装( encapsulation) 、继承( inheritance) 、多态(polymorphism) 、virtual 函数(动态绑定) ……
(3) Template C++。这是C++ 的泛型编程(generic programming) 部分,也是大多数程序员经验最少的部分。Template 相关考虑与设计己经弥漫整个C++,实际上由于templates 威力强大,它们带来崭新的编程范型(programming paradigm) ,也就是所谓的templatemetaprogramming (TMP,模板元编程)
(4) STL。 STL 是个template 程序库,它是非常特殊的一个。它对容器(containers) 、迭代器(iterators) 、算法(algorithms) 以及函数对象(function objects) 的规约有极佳的紧密配合与协调。
记住这个四个次语言,当你从某个次语言切换到另一个,导致高效编程守则要求你改变策略时,不要惊讶。例如:内置(也就是C-like)类型语言pass-by-value通常比pass-by-reference高效,当你从C part of C++ 移往Object-Oriented C++,由于用户自定义构造函数和析构函数的存在,pass-by-reference-to-const往往更好。运用Template C++时尤其如此,因此彼时你甚至不知道所处理的对象的类型,然而一旦跨入STL你就会了解,迭代器和函数对象都是在C指针上塑造出来的,所以对STL的迭代器和函数对象而言,旧时的C pass-by-value守则再次适用。
条款02: 尽量以const, enum, inline替换#define
本条款讨论了C语言中的#define在C++程序设计中的带来的问题并给出了替代方案。
C语言中的宏定义#define只是进行简单的替换,对于程序调试,效率来说,会带来麻烦,在C++中,提倡使用const,enum和inline代替#define;然而,有了consts 、enums 和inlines,我们对预处理器(特别是#define) 的需求降低了,但并非完全消除。#include 仍然是必需品,而#ifdef/#ifndef 也继续扮演控制编译的重要角色。目前还不到预处理器全面引退的时候。
#define定义
#define ASPECT_RATIO 1.653
const定义
const double AspectRatio=1.653
enum定义
enum{NumTurns=5};
inline定义
template<typename T> inline void callWithMax(const T& a,const T& b) { f(a>b?a:b); }
当我们以常量替换#defines,有两种特殊情况值得说说。第一是定义常量指针:
const std::string authorName="Scott Meyers";
第二个值得注意的是class专属常量。为了将常量的作用域限制于class内,你必须让它成为class的一个成员,而为确保次常量至多只有一份实体,比必须让它成为一个static成员
class GamePlayer { private: static const int NumTurns=5; int scores[Numturns]; } //如果编译器不允许你这样做,你可以使用"the enum hack"补偿,enum{NumTurns=5};
请记住:
对于单纯常量,最好以const对象或enum替换#defines
对于形似函数的宏,最好改用inline函数替换#defines