C++. Сборник рецептов - [49]

Шрифт
Интервал

2.2. Обеспечение единственности экземпляра переменной при большом количестве исходных файлов

Проблема

Требуется, чтобы одна и та же переменная использовалась различными модулями программы, а копия переменной должна быть только одна. Другими словами, это должна быть глобальная переменная.

Решение

Объявите и определите как обычно переменную в одном файле реализации, а в других файлах реализации, где требуется доступ к этой переменной, используйте ключевое слово >extern. Часто это означает включение объявлений >extern в заголовочные файлы, используемые файлами реализаций, которым требуется доступ к глобальной переменной. Пример 2.3 содержит несколько файлов, которые показывают, как используется ключевое слово >extern для доступа к переменным, определенным в другом файле реализации.

Пример 2.3. Использование ключевого слова extern


>// global.h

>#ifndef GLOBAL_H__ // см. рецепт 2.0

>#define GLOBAL_H__


>#include


>extern int x;

>extern std::string s;

>#endif


>// global.cpp

>#include


>int x = 7;

>std::string s = "Kangaroo";


>// main.cpp

>#include

>#include "global.h"


>using namespace std;

>int main() {

> cout << "x = " << x << endl;

> cout << "s = " << s << endl;

>}

Обсуждение

Ключевое слово >extern — это способ сказать компилятору, что реальная область памяти для переменной выделяется в другом месте, >extern говорит компоновщику, что переменная описана где-то в другом объектном файле и что компоновщик должен найти ее при создании конечного исполняемого файла или библиотеки. Если компоновщик не находит переменной, объявленной как >extern, или если он находит более одного ее определения, он генерирует ошибку компоновки.

Пример 2.3 не слишком впечатляет, но он хорошо иллюстрирует вопрос. Две мои глобальные переменные объявляются в global.cpp:

>int x = 7;

>std::string s = "Kangaroo";

Мне требуется доступ к ним из других файлов реализации, так что я поместил в заголовочный файл global.h объявление >extern для них:

>extern int x;

>extern std::string s;

Разница между объявлением и определением очень важна. В C++ можно объявить что-либо несколько раз, при условии совпадения объявлений, но определить что-либо можно только один раз. Это называется правилом одного определения (на самом деле в некоторых случаях определить объект можно несколько раз, но только если определения абсолютно идентичны — обычно это бессмысленно). Ключевое слово >extern — это механизм, позволяющий сказать компилятору и компоновщику, что определение находится где-то еще и что оно должно быть разрешено при компоновке.

Нельзя сказать, что использование >extern должно быть постоянным. Его следует использовать обдуманно и только тогда, когда это необходимо, так как оно позволяет создавать переменные, глобальные для всего приложения. Иногда оно может потребоваться для поистине глобальных объектов или данных — объекта журналирования, оборудования, большого объекта общих данных, но в большинстве случаев имеются более адекватные альтернативы.

2.3. Снижение числа #include с помощью предварительного объявления классов

Проблема

Имеется заголовочный файл, который ссылается на классы из других заголовочных файлов, и требуется снизить зависимости компиляции (и, возможно, время).

Решение

Чтобы избежать ненужных зависимостей при компиляции, везде, где только возможно, используйте предварительное объявление классов. Пример 2.4. является коротким примером предварительного объявления класса.

Пример 2.4. Предварительное объявление класса


>// myheader.h

>#ifndef MYHEADER_H__

>#define MYHEADER_H__


>class A; // заголовок для А включать не требуется


>class В {

>public:

> void f(const A& a);

> // ...

>private:

> A* a_;

>};

>#endif

Где-то в другом месте имеется заголовочный файл и, вероятно, файл реализации, который объявляет и определяет класс , но в файле myheader.h подробности класса меня не волнуют: все, что мне требуется знать, — это то, что — это класс.

Обсуждение

Предварительное объявление класса — это способ игнорировать подробности, о которых не требуется беспокоиться. В примере 2.4 myheader.h не должен знать о классе ничего, кроме того, что он существует и что это класс.

Рассмотрим, что случится, если с помощью >#include включить заголовочный файл для , или, что более реально, заголовочный файл для полудюжины или более классов, присутствующих в реальном заголовочном файле. Тогда файл реализации (myheader.cpp) будет включать заголовочный файл myheader.h, так как он содержит все объявления. До сих пор все было хорошо. Но если вы измените один из заголовочных файлов, включаемых в myheader.h (или один из заголовочных файлов, включаемых одним из этих файлов), то потребуется перекомпилировать все файлы реализации, включающие myheader.h.

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

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


Рекомендуем почитать
Изучаем Java EE 7

Java Enterprise Edition (Java EE) остается одной из ведущих технологий и платформ на основе Java. Данная книга представляет собой логичное пошаговое руководство, в котором подробно описаны многие спецификации и эталонные реализации Java EE 7. Работа с ними продемонстрирована на практических примерах. В этом фундаментальном издании также используется новейшая версия инструмента GlassFish, предназначенного для развертывания и администрирования примеров кода. Книга написана ведущим специалистом по обработке запросов на спецификацию Java EE, членом наблюдательного совета организации Java Community Process (JCP)


Pro Git

Разработчику часто требуется много сторонних инструментов, чтобы создавать и поддерживать проект. Система Git — один из таких инструментов и используется для контроля промежуточных версий вашего приложения, позволяя вам исправлять ошибки, откатывать к старой версии, разрабатывать проект в команде и сливать его потом. В книге вы узнаете об основах работы с Git: установка, ключевые команды, gitHub и многое другое.В книге рассматриваются следующие темы:основы Git;ветвление в Git;Git на сервере;распределённый Git;GitHub;инструменты Git;настройка Git;Git и другие системы контроля версий.


Java 7

Рассмотрено все необходимое для разработки, компиляции, отладки и запуска приложений Java. Изложены практические приемы использования как традиционных, так и новейших конструкций объектно-ориентированного языка Java, графической библиотеки классов Swing, расширенной библиотеки Java 2D, работа со звуком, печать, способы русификации программ. Приведено полное описание нововведений Java SE 7: двоичная запись чисел, строковые варианты разветвлений, "ромбовидный оператор", NIO2, новые средства многопоточности и др.


Фундаментальные алгоритмы и структуры данных в Delphi

Книга "Фундаментальные алгоритмы и структуры данных в Delphi" представляет собой уникальное учебное и справочное пособие по наиболее распространенным алгоритмам манипулирования данными, которые зарекомендовали себя как надежные и проверенные многими поколениями программистов. По данным журнала "Delphi Informant" за 2002 год, эта книга была признана сообществом разработчиков прикладных приложений на Delphi как «самая лучшая книга по практическому применению всех версий Delphi».В книге подробно рассматриваются базовые понятия алгоритмов и основополагающие структуры данных, алгоритмы сортировки, поиска, хеширования, синтаксического разбора, сжатия данных, а также многие другие темы, тесно связанные с прикладным программированием.


Питон — модули, пакеты, классы, экземпляры

Python - объектно-ориентированный язык сверхвысокого уровня. Python, в отличии от Java, не требует исключительно объектной ориентированности, но классы в Python так просто изучить и так удобно использовать, что даже новые и неискушенные пользователи быстро переходят на ОО-подход.


Как пасти котов. Наставление для программистов, руководящих другими программистами

«Как пасти котов» – это книга о лидерстве и руководстве, о том, как первое совмещать со вторым. Это, если хотите, словарь трудных случаев управления IT-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.