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

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

, так что ему достаточно только предварительного объявления. Однако если бы в определении класса я использовал функцию-член (метод) или переменную или если бы создавал объект типа , а не только указатель или ссылку на него, то предварительного объявления окажется недостаточно. Причиной этого является то, что файлы, включающие myheader.h, должны знать размер , и если >A является членом , то компилятор, чтобы определить размер , должен знать размер . Указатель или ссылка на что-либо всегда имеют один и тот же размер, так что в случае использования указателей или ссылок подробности об компилятор не интересуют, и, следовательно, заголовочный файл не требуется

Неудивительно, что если включить в myheader.h какое-либо определение, использующее членов >A, то потребуется включить через >#include заголовок для . Это требуется для того, чтобы компилятор мог проверить сигнатуру используемой функции-члена или тип переменной-члена . Вот иллюстрация кода, требующего >#include.

>#include "a.h"


>class B {

>public:

> void f(const A& a) {

>  foo_ = a.getVal(); // требуется знать, допустимо ли a.getVal

> }

>}

>// ...

В общем случае используйте предварительное объявление тогда, когда это позволяет снизить количество >#include, что отражается на времени компиляции.

2.4. Предотвращение конфликта имен с помощью пространств имен

Проблема

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

Решение

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

Пример 2.5. Использование пространств имен


>// Devices.h

>#ifndef DEVICES_H__

>#define DEVICES_H__


>#include

>#include


>namespace hardware {

> class Device {

> public:

>  Device(): uptime_(0), status_("unknown") {}

>  unsigned long getUptime() const;

>  std::string getStatus() const;

>  void reset();

> private:

>  unsigned long uptime_;

>  std::string status_;

> };


> class DeviceMgr {

> public:

>  void getDeviceIds(std::list& ids) const;

>  Device getDevice(const std::string& id) const;

>  // Other stuff...

> };

>}


>#endif // DEVICES_H__


>// Devices.cpp

>#include "Devices.h"

>#include

>#include


>namespace hardware {

> using std::string;

> using std::list;


> unsigned long Device::getUptime() const {

>  return(uptime__);

> }


> string Device::getStatus() const {

>  return(status_);

> }


> void DeviceMgr::getDeviceIds(list& ids) const {}


> Device DeviceMgr::getDevice(const string& id) const {

>  Device d;

>  return(d);

> }

>}


>// DeviceWidget.h

>#ifndef DEVICEWIDGET_H__ #define DEVICEWIDGET_H__

>#include "Devices.h"


>namespace ui {

> class Widget {/*... */ };


> class DeviceWidget : public Widget {

> public:

>  DeviceWidget(const hardware::Device& dev) : device_(dev) {}

>  // Some other stuff

> protected:

>  hardware::Device device_;

> };

>}

>#endif // DEVICEWIDGET_H__


>// main.cpp

>#include

>#include "DeviceWidget.h"

>#include "Devices.h"


>int main( ) {

> hardware::Device d;

> ui::DeviceWidget myWidget(d);

> // ...

>}

Обсуждение

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

Вначале рассмотрим файл Devices.h. Он содержит пару классов, которые управляют элементами оборудования, — >Device и >DeviceMgr. Однако они не должны находиться в глобальном пространстве имен (что означало бы, что их имена видны в любом месте программы), так что я поместил их в пространство имен >hardware.

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

>#define DEVICES_H__


>#include

>#include


>namespace hardware {

> class Device {

>  // ...

> };


> class DeviceMgr {

>  // ...

> };


>}

>#endif // DEVICES_H__

Этот механизм прост: «оберните» все, что требуется поместить в пространство имен, в блок >namespace.

Приведенный выше фрагмент — это объявление >Device и >DeviceMgr, но нам также требуется подумать об их реализациях, которые находятся в файле Devices.cpp. И снова оберните все в блок >namespace — он будет добавлен к уже имеющемуся содержимому этого пространства имен.

>#include "Devices.h"

>#include

>#include


>namespace hardware {

> using std::string;

> using std::list;

> // Реализация Device и DeviceMgr

>}

В данный момент пространство имен >hardware содержит все, что требуется. Все, что осталось, — это где-то его использовать. Для этого имеется несколько способов. Способ, который был использован в примере 2.5, состоит в указании полного имени класса >Device, включая пространство имен, как здесь.


Рекомендуем почитать
Изучаем 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-проектами. Программист подобен кошке, которая гуляет сама по себе. Так уж исторически сложилось. Именно поэтому так непросто быть руководителем команды разработчиков. Даже если вы еще месяц назад были блестящим и дисциплинированным программистом и вдруг оказались в роли менеджера, вряд ли вы знаете, с чего надо начать, какой выбрать стиль руководства, как нанимать и увольнять сотрудников, проводить совещания, добиваться своевременного выполнения задач.