例如 #define ASPECT_RATIO 1.653 记号名称ASPECT_RATIO 也许从未被编译器看见;也许在编译器开始处理源码前就被预处理器移走了。于是记号名称ASPECT_RATIO 可能没进入记号表内。于是当你运用此常量但获得一个编译错误信息时,可能会带来困惑,因为错误信息也许会提到1.653而不是ASPECT_RATIO 。如果ASPECT_RATIO 被定义在一个不是你写的头文件中,你可能对1.653以及它来自何处毫无概念,于是你将因为追踪它而浪费时间。这个问题也可能出现在记号调试器中,原因相同:你使用的名称可能未进入记号表。
当定义一个常量时,常量名称肯定会被编译器看到并进入记号表。对于浮点常量而言,使用常量可能比使用#define导致较小量的码,因为预处理器将宏盲目的替换成值有可能导致目标码出现多份宏的值,若改用常量则不会出现这种情况。当我们用常量代替#define时,需要注意两种特殊情况:第一是定义常量指针;第二是定义class专属常量。 当我们定义常量指针时,有必要将指针也声明为const。对于class的专属常量而言,为了将常量的作用域限制在class内,必须让他成为class的一个成员;而为了确保此常量至多只有一份实体,必须让他成为static成员: class Temp { static const int NUM = 5; }; 通常C++要求你对你所使用的的任何东西提供一个定义式,但如果它是一个class专属常量又是static有是一个整数类型(例如int,char等),则需特殊处理。只要不取它们的地址,你可以声明并使用它们,而无需提供定义式。但如果你需要取其地址或你的编译器必须要看到定义,那么你就必须提供一个定义式(const int Temp::NUM;)。请注意,要把这个式子放入实现文件而非头文件。 对于enum来说,enum hack的行为比较像#define,例如对一个enum取地址是不合法的,即无法使用pointer或reference指向一个enum。the enum hack补偿做法的理论基础是:一个属于枚举类型的数值可以权冲一个ints使用。enum hack是template metaprogramming的基础技术。有一些看起来像函数的宏,可以完成想要的实现,又可以避免函数调用带来的额外开销。以a和b的较大值调用函数f #define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b)) 无论何时,对类似于这种宏中的参数都应该加上小括号,以免他人在表达式中调用该宏时遇到麻烦。但纵使你为所有实参都带上小括号,依然有可能发生不可思议的事情: int a = 5, b = 0; CALL_WITH_MAX(++a, b); //a被累加两次 CALL_WITH_MAX(++a, b+10); //a被累加一次
对于那些行为类似于函数的宏而言,如果可以写出对应的template inline函数,就可以在获得宏带来的效率的同时,也可以获得一般函数的所有可预料行为和类型安全性。const int* a; int const* a;
声明迭代器为const表示这个迭代器不能指向不同的东西,但它所指的东西的值是可以改变的。如果你希望这个迭代器指向的对象不可被改变,应该使用const_iterator。在函数声明时,另函数的返回值类型为const往往可以降低因客户错误而导致的意外,而又不至于放弃安全性和高效性。将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。这类函数的重要性主要体现在两方面:第一、它们使class接口比较容易理解。这是因为,我们可以通过const属性直接得知哪个函数可以改动对象内容而哪个函数不行。第二、它们使操作const对象成为可能。这对编写高效代码是个关键,因为改善C++程序效率的一个根本办法是以pass by reference-to-const方式传递对象,而此技术可行的前提是,我们有const成员函数可用来处理取得(并经修饰而成)的const对象。对于成员函数来说,如果两个成员函数只是常量性不同的话,是可以被重载的。当const和non-const成员函数有着实质等价的实现时,另non-const版本调用const版本可以避免代码重复。关于const成员函数的含义,主要有两个流行概念:bitwise constness(又称physical constness)和logical constness。bitwise constness阵营的人相信,成员函数只有在不更改对象之任何成员变量时才可以说是const,也就是说它不会改变对象内的任意一个bit。logical constness阵营的人则认为,一个const成员函数可以修改它所处理的对象内的某些bits,但只有客户端侦测不出的情况下才可以。mutable可以 释放掉non-static成员变量的bitwise constness约束。函数内的static对象被称为是local static对象(因为它们对于函数而言是local),其他static对象被称为是non-local static对象。 所谓编译单元是指产出单一目标文件的那些源码。基本上它是单一源码文件加上它所包含的头文件。
Singleton模式(单例模式)的一个常见手法是将每个non-local static对象搬到它们的一个专属函数内(该对象在该函数内被声明为static),这些函数返回一个reference指向该对象。这个手法的基础在于:函数内的static对象会在首次遇上该对象的定义式时进行初始化。而且当你以函数调用方式代替直接访问方式时,可以保证你所获得的那个reference指向的一定是一个历经了初始化的对象;若你从未调用这个static的仿真函数,也不会引发构造和析构成本。对于所有的non-const static对象(不管是local或non-local),如果在多线程环境下等待某事发生都会有麻烦发生。处理这个麻烦的一种做法是:在程序的单线程启动阶段,手工调用所有reference-returning函数,这可以消除与初始化有关的竞速形势。