条款1:视C++为一个语言联邦(View C++ as a federation of languages)
C++是个多重泛型编程语言(multiparadigmprogramming language),同时支持过程形式(Multiparadigm programming language)、面向对象形式(object-oriented)、函数形式(functional)、泛型形式(generic)、元编程形式(metaprogramming)。
将C++视为一个由相关语言组成的联邦而非单一语言。C++主要的次语言:
C。C++仍以C为基础。区块(block)、语句(statements)、预处理器(preprocessor)、内置数据类型(built-indata types)、数组(arrays)、指针(pointers)等来自C。C++的高效编程守则映照出C语言的局限:没有模板(templates)、没有异常(exceptions)、没有重载(overloading)…………
Objective-Oriented C++。类(classes)、封装(encapsulation)、继承(inheritance)、多态(polymorphism)、virtual函数(动态绑定)…………
TemplateC++。这是C++泛型编程(generic programming)部分,也是大多数程序员经验最少的地方。
STL。它是一个template程序库,它对容器(containers)、迭代器(iterators)、算法(algorithms)以及函数对象(function objects)的规约有极佳的紧密配合与协调。
条款2:尽量以const, enum, inline替换#define(Prefer consts, enums, and inlines to#defines)
(宁可以编译器替换预处理器)
#defineAPSPECT_RATIO 1.653
记号APSPECT_RATIO也许从未被编译器看见,也许在编译器开始处理源码之前它就被预处理器移走了。记号APSPECT_RATIO未进入符号表。
constdouble AspectRatio = 1.653; //全部大写用于宏
AspectRatio作为一个语言常量,能被编译器看到,会进入符号表。此外,对浮点常量而言,使用常量可能比用#define导致较小的代码量,因为预处理器盲目地将宏名称APSPECT_RATIO替换为1.653,导致目标码出现多份1.653。
当以常量替换#defines,有两种特殊情况注意一下:
一.定义常量指针(constantpointers)。由于常量定义式通常被放在头文件中,因此有必要将指针声明为const。
二.class专属常量。为了将常量的作用域(scope)限制于class内,必须让其成为class的一个成员(member);为确保此常量至多只有一份实体,必须让它成为一个static成员。
classGamePlayer{
private:
static const int NumTurns = 5; //常量声明式
int scores[NumTuns]; //使用该常量
…………
};
const int GamPlayer::NumTurns; //NumTurn的定义
请把这个式子放进一个实现文件而非头文件,由于class常量已在生命时获得初值,因此定义时不可以再设初值。
无法利用#define创建一个class专属常量,因为#define并不重视作用域。
旧式编译器也许不支持上述语法,不允许static成员在其声明式上获得初值。可以将初值放在定义式:
classGamePlayer{
private:
static const int NumTurns ; //static class常量声明,位于头文件内
…………
};
const int GamPlayer::NumTurns = 5; // static class常量定义,位于实现文件内
枚举类型的数值可权充ints使用
classGamePlayer{
private:
enum { NumTurns = 5 } ; //”the enum hack”令NumTurns成为5的一个记号名称
int scores[NumTuns];
…………
};
enum hack 的行为某方面说比较像#define而不像constant。(取一个enum的地址不合法,取一个#define的地址通常也不合法;enum和#define不会导致非必要的内存)
另一个常见的#define误用情况是以它实现宏(macros)。宏看起来像函数,但不会招致函数调用带来的额外开销。(为宏中的所有实参加上小括号)
可以用templateinline函数获得宏带来的效率以及一般函数的所有可预料行为和类型安全性。
有了consts、enums和inlines,我们对预处理器的需求降低了,但并非完全消除。#include仍是必须的,而#ifdef/#ifndef继续扮演控制编译的重要角色。