Программирование >>  Дополнительные возможности наследования 

1 ... 216 217 218 [ 219 ] 220 221 222 ... 265


командами должна следовать команда #endif, которую необходимо установить до завершения блока (до следующей закрывающей фигурной скобки).

Директива #ifdef принимает значение, равное истине, если тестируемая лексема уже была определена. Поэтому можем записать следующее:

ftifdef DEBUG

cout Строка DEBUG определена ; #endif

Когда препроцессор читает директиву #ifdef, он проверяет построенную им самим таблицу, чтобы узнать, была ли уже определена в профамме лексема DEBUG. Если да, то #ifdef возвращает значение true, и все, что находится до следующей директивы #else или #endif, записывается в промежуточный файл для компиляции. Если эта директива возвращает значение false, то ни одна строка кода, находящаяся между директивами #ifdef DEBUG и #endif, не будет записана в промежуточный файл, т.е. вы получите такой вариант промежуточного файла, как будто этих сфок никогда и не было в исходном коде.

Обратите внимание, что директива #ifndef является логической противоположностью директивы #ifdef. Директива flifndef возвращает true в том случае, если до этой точки в профамме заданная лексема не была определена.

Команда препроцессора #else

Как вы правильно предположили, директиву #else можно вставить между #ifdef (или flifndef) и завершающей директивой #endif. Использование этих директив показано в листинге 21.1.

Листинг 21.1. Исипльзпванив директивы #def ine

12 13 14 15 16 17 18 19 20 21

#define DemoVersion #define NOERSION 5 #include <iostream.h>

int main() {

cout Checking on the definitions of DemoVersion, NT VERSION and WINDOWS VERSION .\ n ;

#ifdef DemoVersion

cout << DemoVersion defined.\ n ; #else

cout DemoVersion not defined.\ n ; #endif

#ifndef NT VERSION

cout << NT VERSION not defined!\ n ; #else

cout NT VERSION defined as: NT VERSI0N endl; #endif



22 23 24 25 26 27 28 29 30 31

Kifdef WINDOWSVERSION

cout WINDOWS ,VERSION (lefinod!\ iV, ttelse

coul << WINDOWS VERSION was nol d(:1incd,\ iV ftendif

cout << Do[ie.\ n ; return 0;

Г., hecking on the dufiiuUons of DomoVcrsion, NT VERSION and WINDOWS VERSION, . .

DemoVersion defined. NT VERSION defined as; 5 WINDOWS VERSION was not defined Done,

/ В строках 1 и 2 определяются лексемы DemoVersion и NT VERSION, причем

лексеме NT VERSION назначается литерал 5. В строке 11 проверяется определение лексемы DemoVersion, а поскольку она определена (хотя и без значения), то результат тестирования принимает истинное значение и строка 12 выводит соответствующее сообщение.

В строке 17 определенность лексемы NT VERSION проверяется с помощью директивы #ifndef. Поскольку данная лексема определена, возвращается значение false и выполнение программы продолжается со строки 20. Именно здесь слово NT VERSION заменяется символом 5, т.е. компилятор воспринимает эту строку кода в следующем виде:

cout NOERSI0N defined as; 5 endl

Обратите внимание, что первое слово в сообшении NT VERSION не замешается строкой 5, поскольку является частью текстовой строки, заключенной в кавычки. Но лексема NTVERSION между операторами вывода замешается; таким образом, компилятор видит вместо нее символ 5, точно так же, как если бы вы ввели этот символ в выражение вывода.

Наконец, в строке 23 программа проверяет определенность лексемы WINDOWS VERSION. Поскольку эта лексема в программе не определена, возвращается значение false и строкой 26 выводится соответствующее сообщение.

Включение файлов и предупреждение пшнбпк включения

Вы обязательно будете создавать проекты, состоящие из нескольких различных файлов. Традиционно в проектах приложения каждый класс имеет собственный файл заголовка с объявлением класса (обычно такие файлы имеют расширение hpp) и файл источника с кодом выполнения методов класса (обычно с расширением . срр).



функцию main о программы помещают в свой собственный файл срр, а все файлы срр компилируются в файлы obj, которые затем компоновщик связывает в единую профамму.

Поскольку профаммы обычно используют методы из многих классов, основной файл профаммы будет содержать включения многих файлов заголовков. Кроме того, файлы заголовков часто включают в себя другие файлы заголовков. Например, файл заголовка с объявлением производного класса должен включить файл заголовка базового класса.

Представьте себе, что класс Animal объявляется в файле ANIMAL.hpp. Чтобы объявить класс Dog (который производится от класса Animal), следует в файл DOG.HPP включить файл ANIMAL, hpp, в противном случае класс Dog нельзя будет произвести от класса Animal. Файл заголовка Cat также включает файл ANIMAL, hpp по той же причине.

Если существует метод, который использует оба класса - Cat и Dog, то вы столкнетесь с опасностью двойного включения файла ANIMAL.hpp. Это сгенерирует ошибку в процессе компиляции, поскольку компилятор не позволит дважды объявить класс Animal, даже несмотря на идентичность объявлений. Эту проблему можно решить с помощью директив препроцессора. Код файла заголовка ANIMAL необходимо заключить между следующими директивами:

#ifndsf ANIMAL.HPP ffdefine ANIMAL.HPP

далее следует код файла заголовка

ffendif

Эта запись означает: если лексема ANIMAL.HPP еше не определена в профамме, продолжайте выполнение кода, следующая строка которого определяет эту лексему, Между директивой #define и директивой завершения блока условной компиляции #endif включается содержимое файла заголовка.

Когда ваша профамма включает этот файл в первый раз, препроцессор читает первую строку и результат проверки, конечно же, оказывается истинным, т.е. до этого момента лексема еше не была определена как ANIMAL.HPP. Следующая директива препроцессора #def ine определяет эту лексему, после чего включается код файла.

Если профамма включает файл ANIMAL,НРР во второй раз, препроцессор читает первую строку, которая возвращает значение FALSE, поскольку строка ANIMAL, hpp уже была определена. Поэтому управление программой переходит к следующей директиве - #else (в данном случае таковая отсутствует) или #endif (которая находится в конце файла). Следовательно, в этот раз пропускается все содержимое файла и класс дважды не объявляется.

Совершенно не важно реальное имя лексемы (в данном случае ANIMAL.HPP), хотя общепринято использовать имя файла, записанное прописными буквами, а точка (.), отделяющая имя от расширения, заменяется при этом символом подчеркивания. Однако это не закон, а общепринятое соглашение, которое следует рассматривать лишь как рекомендацию.


примечание

Никогда не повредит использовать средства защиты от многократного включения. Нередко они способны сэкономить часы работы, потраченные на поиск ошибок и отладку программы.



1 ... 216 217 218 [ 219 ] 220 221 222 ... 265

© 2006 - 2025 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика