C++ Программирование в среде С++ Builder 5

Пространства имен


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

Язык C++ решает эту проблему, позволяя разбить проект на сегменты с различными пространствами имен (namespaces). Заключив свои символы в отдельное пространство имен, вы, по существу, снабжаете имя всякого типа, переменной и т. д. некоторым скрытым префиксом. Например, если определить пространство имен

namespace MYSPACE { int х;

}

то переменная х будет существовать в пространстве имен MYSPACE. Любые другие переменные х, принадлежащие глобальной области действия или другому пространству имен, не будут с ней конфликтовать. Чтобы явно обратиться к переменной, применяется операция разрешения области действия:

MYSPACE::х = 11;

Пространства имен могут быть вложенными:

namespace OUTER { int x;

namespace INNER { int x;

}

Соответственно, чтобы ссылаться на эти переменные, нужно будет написать:

OUTER::х = 11;

OUTER::INNER::x = 22;



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

Создание пространства имен

К созданию именных пространств можно отнести три момента:

  • Первоначальное объявление пространства.
  • Расширение пространства имен.
  • Определение анонимного пространства.
  • Первоначальное объявление пространства имен — это определение пространства с именем, еще не встречавшимся в программе. Синтаксис его следующий:

    namespace новое_имя {тело пространства имен}

    Тем самым в программе объявляется пространство имен с именем новое_имя.

    Объявленное пространство имен можно расширять, в том же исходном файле или любом другом, применяя ту же конструкцию, но с уже имеющимся именем:

    namespace существующее_имя [тело_пространства__имен]


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

    Синтаксис C++ позволяет определять анонимные пространства имен:

    namespase{

    int x;

    double у;

    }

    Все анонимные пространства имен в глобальной области действия данного файла составляют единое целое. Говоря проще, объявление глобальных символов как относящихся к анонимному пространству имен эквивалентно их объявлению с модификатором static:

    static int x;

    static double у;



    Доступ к пространству имен



    Доступ к элементам конкретного пространства имен может осуществляться тремя способами:

  • Путем явной квалификации имени.


  • Посредством квалифицирующего объявления.


  • С помощью директивы using.


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

    Квалифицирующее объявление выглядит следующим образом:

    using иденгификатор_пространства_имен::имя;

    Элемент указанного пространства имен, идентифицируемый именем, объявляется как принадлежащий локальной области действия. После этого все не квалифицированные ссылки на имя будут рассматриваться как относящиеся к данному элементу. Вот пример:

    namespace ALPHA {

    int RetJ(int j) {return j;} } namespace BETA {

    int RetJ(int j) {return (j * 2);}

    }

    int main(void) {

    using BETA::RetJ; // Квалифицирующее объявление RetJ().

    int x = 11;

    printf("Calling RetJ(): %d\n"/ RetJ(x));

    // Вызывает BETA::RetJ(). return 0;

    }

    Последняя форма доступа к пространству имен — директива using. Она имеет вид:

    using namespace идентификатор пространства_имен;

    В результате указанное пространство имен будет приниматься по умолчанию, если ссылка на некоторое имя не может быть разрешена локально (как и в общем случае, локальное объявление скрывает любое объявление в “более внешней” области действия). Вот пример, демонстрирующий различные моменты применения именных пространств:



    #include <stdio.h>

    namespace ALPHA {

    int x = 11;

    int у = 111;

    int v = 1111;

    } namespace BETA {

    int x = 22;

    int у - 222;

    int z = 2222;

    }

    int main(void) {

    using namespace ALPHA; // Конфликта не возникает до

    using namespace BETA; // момента действительного

    // обращения к элементам х и у.

    using ВЕТА::х;

    // Локальная квалификация х.

    int z = 3333; // Локальная переменная.

    printf ("Global х = %d, у = %d, z = %d, v = %d.\n", х, ALPHA::y, ::z, v);

    // х квалифицирована

    // локально, у - явно.

    printf("Local z = %d.\n", z) ;

    return 0;

    }

    Программа печатает:

    Global х = 22, у = 111, z = 2222, v = 1111. Local z = 3333.

    Здесь показан случай, когда могут возникать конфликты между двумя пространствами имен, используемыми одновременно. В теле главной процедуры указаны два именных пространства ALPHA и BETA, которые оба объявляют глобальные переменные х и у. В данный момент у компилятора не возникает никаких возражений. Ошибка случилась бы, например, если ниже мы обратились к переменной у без какой-либо квалификации. В общем, разберите внимательно этот пример — каким образом компилятор разрешает неоднозначные ссылки на различные символы.



    Псевдонимы именных пространств



    Можно объявлять псевдонимы для именных пространств, если, например, полная квалификация символа оказывается слишком уж длинной:

    namespace BORLAND_INTERNATIONAL

    {

    // Тело именного пространства...

    namespace NESTED_BORLAND_INTERNATIONAL

    {

    // Тело вложенного именного пространства... }

    // Псевдонимы:

    namespace BI = BORLAND_INTERNATIONAL;

    namespace NBI = BORLAND_INTERNATIONAL::

    NESTED_BORLAND_INTERNATIONAL;


    Содержание раздела