Будучи языковой константой, AspectRatio видима компилятору и, естественно, помещается в таблицу символов. К тому же в случае использования константы с плавающей точкой (как в этом примере) генерируется более компактный код, чем при использовании #define. Дело в том, что препроцессор, слепо подставляя вместо макроса ASPECT_RATIO величину 1.653, создает множество копий 1.653 в объектном коде, в то время как использование константы никогда не породит более одной копии этого значения.
При замене #define константами нужно помнить о двух особых случаях. Первый касается константных указателей. Поскольку определения констант обычно помещаются в заголовочные файлы (где к ним получает доступ множество различных исходных файлов), важно, чтобы сам
const char * const authorName = “Scott Meyers”;
Более подробно о сущности и применений слова const, особенно в связке с указателями, см. в правиле 3. Но уже сейчас стоит напомнить, что объекты типа string обычно предпочтительнее своих прародителей – строк типа char *, поэтому authorName лучше определить так:
const std::string authorName(“Scott Meyers”);
Второе замечание касается констант, объявляемых в составе класса. Чтобы ограничить область действия константы классом, необходимо сделать ее членом класса, и чтобы гарантировать, что существует только одна копия константы, требуется сделать ее
class GamePlayer {
private:
static const int NumTurns = 5; // объявление константы
int scores[NumTurns]; // использование константы
...
};
То, что вы видите выше, – это
const int GamePlayer::NumTurns; // определение NumTurns; см. ниже,
// почему не указывается значение
Поместите этот код в файл реализации, а не в заголовочный файл. Поскольку начальное значение константы класса представлено там, где она объявлена (то есть NumTurns инициализировано значением 5 при объявлении), то в точке определения задавать начальное значение не требуется.
Отметим, кстати, что нет возможности объявить в классе константу посредством #define, потому что #define не учитывает области действия. Как только макрос определен, он остается в силе для всей оставшейся части компилируемого кода (если только где-то ниже не встретится #undef). Это значит, что директива #define неприменима не только для объявления констант в классе, но вообще не может быть использована для обеспечения какой бы то ни было инкапсуляции, то есть придать смысл выражению «private #define» невозможно. В то же время константные данные-члены могут быть инкапсулированы, примером может служить NumTurns.
Старые компиляторы могут не поддерживать показанный выше синтаксис, так как в более ранних версиях языка было запрещено задавать значения статических членов класса во время объявления. Более того, инициализация в классе допускалась только для целых типов и для констант. Если вышеприведенный синтаксис не работает, то начальное значение следует задавать в определении:
class CostEstimate {
private:
static const double FudgeFactor; // объявление статической константы
... // класса – помещается в файл заголовка
};
const double // определение статической константы
CostEstimate::FudgeFactor = 1.35; // класса – помещается в файл реализации