Главная » C++, C++ Builder » Небольшое отступление: С++ и именованные области видимости

0

Мы уже рассматривали два способа работы с именованными областями (namespaces) в STL, тем не менее крайне важно для вас понять последующее рассуждение. В C++ namespace — что-то вроде сверхкласса, который содержит вложенные классы. Например, так мы создаем сверхкласс с именем fred:

namespace fred

{

class A

{

}

class B

{

}

}

Код содержит два подкласса, определенные как class A и class B. Область namespace — это просто класс, в котором все поля являются общими (public). Таким образом к классу A внутри fred можно обращаться как к fred::A, а к классу B как fred::B. Почему это важно? Представьте, что у вас в библиотеке находится класс, описанный таким образом (в данном случае мы проигнорируем факт, что ваш менеджер не дал бы вам называть классы просто A и B). Предположим теперь, что вам нужно подключить к проекту внешнюю (third-party) библиотеку. Эта внешняя библиотека поставляется без исходников и содержит в себе следующее описание:

namespace thirdpartylib

{

class A

{

}

class B

{

}

}

Очевидно, у вас появляются проблемы. Есть два конфликтующих класса A и два класса B, так что вам нужно пройтись по всему вашему исходному коду и поменять эти имена, а также изменить эти имена на новые в классах, которые на них ссылаются, не говоря уже о функциях, которые с ними работают. Ведь так? Слава богу, нет. В этих двух примерах используются различные именованные области (namespaces), так что, к примеру, для обращения к вашему классу A вам придется написать fred::A. Для обращения к классу A из внешней библиотеки нужно использовать выражение thirdpartylib::A. Эти два имени являются различными с точки зрения компилятора, так что все будет работать так, как и задумывалось.

Однако я слышу глухой стон, вырывающийся из вашей груди. Вы решили, что в коде классов A и

B вам постоянно придется писать примерно следующие страшные конструкции:

// Конструктор класса A в области fred fred::A::A(void)

{

}

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

namespace fred

{

// Конструктор класса A в области fred A::A(void)

{

}

}

Заметьте, что вы можете неоднократно открывать и закрывать блок namespace в одном и том же файле. Все эти разрозненные куски будут помещены вместе в одну область. Например, если у вас два класса определены в одном и том же исходном файле, но в разных областях namespace (вряд ли вы станете так делать, но теоретически у вас такая возможность есть), то вы можете написать:

namespace fred // Открываем область fred

{

// Код в области fred

} // Закрываем область fred

namespace george // Открываем область george

{

// Код в области george

} // Закрываем область george

// Еще какой-нибудь код

Есть еще одна деталь насчет именованных областей (namespaces). Если вам нужно использовать класс, определенный в другой области namespace, вы можете подумать что достаточно написать что-нибудь такое:

namespace fred

{

class george::A; // Импорт класса A из namespace george

class Foo

{

george::A aGeorgeA;

}

}

К сожалению, приведенный выше код не сработает. Хотя в основном  к  областям  namespace можно относиться как к некой надклассовой структуре («сверхкласс»), на самом деле эти области таковыми не являются. В один и тот же момент может быть открыта только одна область, и нельзя использовать модификаторы namespace в ссылках на еще не определенные классы («ссылки вперед»). Как же вам справиться с такой задачей? Ответ очевиден, если только вдуматься в проблему. Вы закрываете одну область namespace и открываете другую.

namespace fred

{

// Внутренние описания области fred

}

namespace george

{

class A; // Описание класса A,

// который будет определен дальше

}

// Теперь вы можете написать

namespace fred

{

class A

{

george::A aGeorgeA;

}

}

Приведенный код будет компилироваться любым стандартным компилятором ANSI C++ (к которым относится и CBuilder) и замечательно работать. Все это приводит нас к следующей дискуссии о том, что такое оператор using и почему его использовать не нужно.

Источник: Теллес М. – Borland C++ Builder. Библиотека программиста – 1998

По теме:

  • Комментарии