第一章 让自己习惯C++
Accustoming Yourself to C++
条款01:视C++为一个语言联邦
View C++ as a federation of languages
一开始C++只是C加上一些面向对象特性,但随着这个语言逐渐成熟,它开始接受不同于C with classes的各种观念,特性和变成战略.Exception对函数的结构化带来不同的做法,templates引入新的设计思考方式,STL定义了前所未见的伸展性做法.
最简单的方法是将C++视为一个由相关语言组成的联邦而非单一语言.C++主要有以下四个次语言:
1.C.C++是以C为基础.区块blocks,语句statements,预处理器preprocessor,内置数据类型built-in data types,数组arrays,指针pointer等都来自C.许多时候C++对问题的解法就是较高级的C解法,但以C++内的C成分工作时,高效编程则映照出C语言的局限:没有模板,没有异常,没有重载...
2.Object-Oriented C++.这部分也就是C with classes所诉求的:classes(包括构造函数和析构函数),封装(encapsulation),继承(inheritance),多态(polymorphism),virtual 函数(动态绑定)...等等.
3.Template C++.这是C++的泛型编程(generic programming)部分.
4.STL.STL是个templates程序库.它对容器containers,迭代器iterators,算法algorithms以及函数对象function objects的规约有极佳的紧密配合与协调.
当从某个次语言切换到另一个时,高效编程则要求改变策略.例如对内置类型而言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再次适用.
注意:C++高效编程守则视情况而变化,取决于使用C++的哪一部分.
条款02:尽量以 const,enum,inline 替换 #define
Prefer consts,enums,and inlines to #define
这个条款或许改为"宁可以编译器替换预处理器"比较好,因为或许#define不被视为语言的一部分,那正是问题所在,当做出以下事情:
#define ASPECT_RATIO 1.653
记号名称ASPECT_RATIO也许从未被编译器看见;也许在编译器开始处理源代码之前它就被预处理器移走了.于是ASPECT_RATIO可能没有进入记号表(symbol table)内.于是运用此常量但获得一个编译错误时,可能会带来困惑,因为这个错误信息也许提到1.653而不是ASPECT_RATIO.
解决的办法是以一个常量替换上述的宏(#define):
const double AspectRatio = 1.653;
作为一个语言常量,AspectRatio可能会被编译器看到,一定会进入记号表内.此外对于浮点常量而言,使用常量可能会比使用#define导致较小量的代码,因为预处理器"盲目地将宏名称ASPECT_RATIO替换为1.653"可能导致目标码出现多份1.653,若是改用常量则不会出现这种情况.
当以常量替换#define,有两种特殊情况值得说说:
第一个是定义常量指针(constant pointers).由于常量定义式通常被放在头文件(以便被不同的源码含入),因此有必要将指针声明为const.例如若要在文件内定义一个常量的char*-base字符串,必须写 const 两次:
const char *const authorName = "Scott Meyers";
关于 const 的意义和使用(特别是当它与指针结合时),条款3有完整的讨论.string对象通常比其前辈char*-base合宜,所以上述的authorName往往定义这样更好:
const std::string authorName("Scott Meyers");
第二个值得注意的是 class 专属常量.为了将常量的作用域限制于 class 内,必须让它成为 class 的一个成员;而为确保此变量至多只有一份实体,必须让它成为一个 static 成员:
class GamePlayer { private: static const int NumTurns = 5; int scores[NumTurns]; };
然而看到的是NumTurn的声明式而非定义式.通常C++要求对所使用的任何东西提供一个定义式,但如果它是个 class 专属常量又是 static 且为整数类型,则需要特殊处理.只要不取它们的地址,可以声明并使用它们而无须提供定义式.但如果取出某个 class 专属常量的地址,就必须提供定义式如下:
const int GamePlayer::NumTurns ;
由于 class 常量已在声明时获取初值,因此定义时不可以再设初值.
注意:
对于单纯变量,最好以 const 对象或 enums 替换#define.
对于形似函数的宏,最好改用 inline 函数替换#define.
版权声明:本文为博主原创文章,未经博主允许不得转载。