分类: C/C++
2009-09-19 12:53:56
#define ASPECT_RATIO 1.653
const double ASPECT_RATIO = 1.653;
const char * const authorName = "Scott Meyers";
另外,定义某个类(class)的常量一般也很方便,只有一点点不同。要把常量限制在类中,首先要使它成为类的成员;为了保证常量最多只有一份拷贝,还要把它定义为静态成员:
class GamePlayer { private: static const int NUM_TURNS = 5; // constant eclaration int scores[NUM_TURNS]; // use of constant ... };
const int GamePlayer::NUM_TURNS; // mandatory definition; // goes in class impl.file
你不必过于担心这种小事。如果你忘了定义,链接器会提醒你。
旧一点的编译器会不接受这种语法,因为它认为类的静态成员在声明时定义初始值是非法的;而且,类内只允许初始化整数类型(如:int, bool, char 等),还只能是常量。
在上面的语法不能使用的情况下,可以在定义时赋初值:
class EngineeringConstants { // this goes in the class private: // header file static const double FUDGE_FACTOR; ... }; // this goes in the class implementation file const double EngineeringConstants::FUDGE_FACTOR = 1.35;
大多数情况下你只要做这么多。唯一例外的是当你的类在编译时需要用到这个类的常量的情况,例如上面GamePlayer::scores数组的声明(编译过程中编译器一定要知道数组的大小)。所以,为了弥补那些(不正确地)禁止类内进行整型类常量初始化的编译器的不足,可以采用称之为“借用enum”的方法来解决。这种技术很好地利用了当需要int类型时可以使用枚举类型的原则,所以GamePlayer也可以象这样来定义:
class GamePlayer { private: enum { NUM_TURNS = 5 } // "the enum hack" — makes // NUM_TURNS a symbolic name // for 5 int scores[NUM_TURNS];// fine };
除非你正在用老的编译器(即写于1995年之前),你不必借用enum。当然,知道有这种方法还是值得的,因为这种可以追溯到很久以前的时代的代码可是不常见的哟。
回到预处理的话题上来。另一个普遍的#define指令的用法是用它来实现那些看起来象函数而又不会导致函数调用的宏。典型的例子是计算两个对象的最大值:
#define max(a,b) ((a) > (b) ? (a) : (b))
int a = 5, b = 0; max(++a, b);// a 的值增加了2次 max(++a, b+10); // a 的值只增加了1次
这种情况下,max内部发生些什么取决于它比较的是什么值!
幸运的是你不必再忍受这样愚笨的语句了。你可以用普通函数实现宏的效率,再加上可预计的行为和类型安全,这就是内联函数(见):
inline int max(int a, int b) { return a > b ? a : b; }
不过这和上面的宏不大一样,因为这个版本的max只能处理int类型。但模板可以很轻巧地解决这个问题:
templateinline const T& max(const T& a, const T& b) { return a > b ? a : b; }
这个模板产生了一整套函数,每个函数拿两个可以转换成同种类型的对象进行比较然后返回较大的(常量)对象的引用。因为不知道T的类型,返回时传递引用可以提高效率(见)。
顺便说一句,在你打算用模板写象max这样有用的通用函数时,先检查一下标准库(见),看看他们是不是已经存在。比如说上面说的max,你会惊喜地发现你可以后人乘凉:max是C++标准库的一部分。
有了const和inline,你对预处理的需要减少了,但也不能完全没有它。抛弃#include的日子还很远,#ifdef/#ifndef在控制编译的过程中还扮演重要角色。预处理还不能退休,但你一定要计划给它经常放长假。