Чтение онлайн

на главную

Жанры

Освой самостоятельно С++ за 21 день.

Либерти Джесс

Шрифт:

hecking on the definitions of DemoVersion, 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 << " NT_VERSION defined as: " << 5 << endl:

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

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

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

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

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

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

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

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

#ifndef ANIMAL_HPP

#define ANIMAL_HPP

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

#endif

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

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

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

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

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

Макросы

Директиву #define можно также использовать дгш создания макросов. Макрос — это лексема, созданная с помощью директивы #define. Он принимает параметры подобно обычной функции. Препроцессор заменяет строку подстановки любым заданным параметром. Например, макрокоманду TWICE можно определить следующим образом:

#define TWICE(x) ( (x) * 2 )

А затем в программе можно записать следующую строку:

TWICE(4)

Целая строка TWICE(4) будет удалена, а вместо нее будет стоять значение 8! Когда препроцессор считывает параметр 4, он выполняет следующую подстановку: ((4) * 2), это выражение затем вычисляется как 4 * 2 и в результате получается число 8.

Макрос может иметь больше одного параметра, причем каждый параметр в тексте замены может использоваться неоднократно. Вот как можно определить два часто используемых макроса — МАХ и MIN:

#define MAX(x,y) ( (x) > (у) ? (x) : (у) )

#define MIN(x,y) ( (x) < (у) ? (x) : (у) )

Обратите внимание, что в определении макроса открывающая круглая скобка для списка параметров должна немедленно следовать за именем макроса, т.е. между ними не должно быть никаких пробелов. Препроцессор, в отличие от компилятора, не прощает присутствия ненужных пробелов. Если записать

#define MAX (x,y) ( (x) > (у) ? (x) : (у) )

и попытаться использовать макрос МАХ

int x = 5, у = 7, z;

Поделиться:
Популярные книги

Ты всё ещё моя

Тодорова Елена
4. Под запретом
Любовные романы:
современные любовные романы
7.00
рейтинг книги
Ты всё ещё моя

Его наследник

Безрукова Елена
1. Наследники Сильных
Любовные романы:
современные любовные романы
эро литература
5.87
рейтинг книги
Его наследник

Долг

Кораблев Родион
7. Другая сторона
Фантастика:
боевая фантастика
5.56
рейтинг книги
Долг

Эйгор. В потёмках

Кронос Александр
1. Эйгор
Фантастика:
боевая фантастика
7.00
рейтинг книги
Эйгор. В потёмках

Играть, чтобы жить. Книга 1. Срыв

Рус Дмитрий
1. Играть, чтобы жить
Фантастика:
фэнтези
киберпанк
рпг
попаданцы
9.31
рейтинг книги
Играть, чтобы жить. Книга 1. Срыв

Смерть может танцевать 2

Вальтер Макс
2. Безликий
Фантастика:
героическая фантастика
альтернативная история
6.14
рейтинг книги
Смерть может танцевать 2

Сотник

Ланцов Михаил Алексеевич
4. Помещик
Фантастика:
альтернативная история
5.00
рейтинг книги
Сотник

Безумный Макс. Ротмистр Империи

Ланцов Михаил Алексеевич
2. Безумный Макс
Фантастика:
героическая фантастика
альтернативная история
4.67
рейтинг книги
Безумный Макс. Ротмистр Империи

Темный Патриарх Светлого Рода 7

Лисицин Евгений
7. Темный Патриарх Светлого Рода
Фантастика:
фэнтези
попаданцы
аниме
5.00
рейтинг книги
Темный Патриарх Светлого Рода 7

Приручитель женщин-монстров. Том 5

Дорничев Дмитрий
5. Покемоны? Какие покемоны?
Фантастика:
юмористическое фэнтези
аниме
5.00
рейтинг книги
Приручитель женщин-монстров. Том 5

Физрук: назад в СССР

Гуров Валерий Александрович
1. Физрук
Фантастика:
попаданцы
альтернативная история
5.00
рейтинг книги
Физрук: назад в СССР

Идеальный мир для Социопата 3

Сапфир Олег
3. Социопат
Фантастика:
боевая фантастика
6.17
рейтинг книги
Идеальный мир для Социопата 3

Воевода

Ланцов Михаил Алексеевич
5. Помещик
Фантастика:
альтернативная история
5.00
рейтинг книги
Воевода

Последняя Арена 6

Греков Сергей
6. Последняя Арена
Фантастика:
рпг
постапокалипсис
5.00
рейтинг книги
Последняя Арена 6