#endif // DEVICEWIDGET_H__
// main.cpp
#include <iostream>
#include 'DeviceWidget.h'
#include 'Devices.h'
int main( ) {
hardware::Device d;
ui::DeviceWidget myWidget(d);
// ...
}
Пример 2.5 более сложен, но давайте разберем его по частям, так как он иллюстрирует несколько ключевых моментов, связанных с пространствами имен. Представьте, что вы пишете управляющее приложение, которое должно взаимодействовать с различным оборудованием. С целью устранения конфликтов имен вы можете разбить это приложение на два или более пространств имен или просто разделить его логически на две части.
Вначале рассмотрим файл Device
и DeviceMgr
. Однако они не должны находиться в глобальном пространстве имен (что означало бы, что их имена видны в любом месте программы), так что я поместил их в пространство имен hardware
.
#ifndef DEVICES_H__ // см. рецепт 2.0
#define DEVICES_H__
#include <string>
#include <list>
namespace hardware {
class Device {
// ...
};
class DeviceMgr {
// ...
};
}
#endif // DEVICES_H__
Этот механизм прост: «оберните» все, что требуется поместить в пространство имен, в блок namespace
.
Приведенный выше фрагмент — это объявление Device
и DeviceMgr
, но нам также требуется подумать об их реализациях, которые находятся в файле namespace
— он будет добавлен к уже имеющемуся содержимому этого пространства имен.
#include 'Devices.h'
#include <string>
#include <list>
namespace hardware {
using std::string;
using std::list;
// Реализация Device и DeviceMgr
}
В данный момент пространство имен hardware
содержит все, что требуется. Все, что осталось, — это где-то его использовать. Для этого имеется несколько способов. Способ, который был использован в примере 2.5, состоит в указании полного имени класса Device
, включая пространство имен, как здесь.
#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) {}
// Other stuff...
protected:
hardware::Device device_;
};
}
#endif // DEVICEWIDGET_H__
Также я использую этот способ в main
в
int main() {
hardware::Device d;
ui::DeviceWidget myWidget(d);
}
Чтобы добавить к одному из пространств имен типы, объявите заголовочный файл и файл реализации так, как показано в примере 2.5. При каждом использовании блока пространства имен, обрамляющего код, этот код добавляется в это пространство имен, так что в пространстве имен может находиться код, который ничего не знает о другом коде этого же пространства имен.
При использовании подхода с указанием полных имен классов, включающих пространство имен, вы быстро устанете вводить код. Имеется пара способов устранить эту проблему. Для полного имени типа с помощью ключевого слова using
можно создать псевдоним.
using hardware::Device;
int main() {
Device d; // Пространство имен не требуется
ui::DeviceWidget myWidget(d);
}
В последующем коде вместо ввода полного имени можно просто сослаться на этот псевдоним. Или можно с помощью using
импортировать все содержимое пространства имен, а не только один содержащийся в нем тип.
using namespace hardware;
int main() {