При разработке приложений на C++ могут возникать некоторые специфические ситуации, например, дважды используемые имена переменных или функции, определенные с одними и теми же прототипами и т.д.
Когда возникают такие сценарии, компилятору становится трудно вывести правильный вызов переменной или функции, что приводит к неоднозначности.
Что такое пространство имен?
Давайте посмотрим на приведенный ниже пример:
1 2 3 4 5 6 7 8 9 |
#include <iostream> #include <string> int main() { int var; double var; std::cin>>var; } |
Вывод данных:
1 2 3 |
In function ‘int main()’: 8:10: error: conflicting declaration ‘double var’ 7:7: note: previous declaration as ‘int var’ |
В приведенном выше примере мы определили две переменные с разными типами, но с одним и тем же идентификатором. Итак, когда мы компилируем этот пример, мы получаем ошибку, как показано в окне вывода. Эти конфликтующие объявления возникают из-за того, что один и тот же идентификатор используется для именования двух переменных.
Этот тип ситуаций приводит к неоднозначности в приложениях.
C++ вводит так называемые «namespaces» для решения этой проблемы. Пространство имен в C++ похоже на пакет, область или библиотеку, которые используются для различения переменных или функций с одинаковыми идентификаторами.
Пространство имен может содержать переменные, функции, классы или другие объекты и даже другое пространство имен. На каждого члена пространства имен можно ссылаться, используя пространство имен. Это помогает компилятору различать различные объекты программирования, даже если они имеют одинаковые имена.
Определение пространства имен
В C++ мы можем определить пространство имен, используя ключевое слово namespace, как показано ниже:
1 2 3 |
namespace namespace_name{ namespace_declarations; } |
Итак, если нам нужно определить пространство имен с именем «test_space», мы можем сделать это, как показано ниже:
1 2 3 |
namespace test_space{ int var=10; } |
Приведенное выше объявление определяет пространство имен с именем «test_space». Как показано, он имеет целочисленную переменную var в качестве члена.
Доступ к членам пространства имен
Теперь мы определили собственное пространство имен «test_space», но как нам получить доступ к содержимому этого пространства имен?
В программе C++ мы можем получить доступ к членам пространства имен, используя синтаксис:
1 |
namespace_name::namespace_member; |
Таким образом, целочисленная переменная var, объявленная в пространстве имен «test_space» выше, может быть доступна следующим образом:
1 |
test_space::var; |
Вот полный пример, который демонстрирует использование пространства имен:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include <iostream> #include <string> namespace test_space{ int var = 10; } int main() { double var = 20.53; std::cout<<"local var = "<<var<<std::endl; std::cout<<"test_space::var = "<<test_space::var; return 0; } |
Вывод данных:
1 2 |
local var = 20.53 test_space::var = 10 |
Мы продемонстрировали вам создание и доступ к пространству имен в приведенном выше примере программирования. Как вы можете видеть, «test_space» — это пространство имен, которое мы определили. В нем определена одна целочисленная переменная var. Затем в основной функции у нас есть еще одна двойная переменная var, которая инициализируется.
Позже мы отобразим обе эти переменные. Обратите внимание, что хотя локальная двойная переменная внутри main может быть напечатана напрямую, для печати переменной пространства имен мы должны предварять ее именем пространства имен.
Это также решило проблему конфликтов между переменными из-за тех же имен, которые мы обсуждали ранее.
Использование директивы
Как вы уже поняли, мы можем получить доступ к членам пространства имен, используя namespace_name::namespace_member.
Но если мы не хотим указывать имя пространства имен везде в программе, мы можем использовать директиву «using», чтобы включить пространство имен в программу.
Это делается следующим образом:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#include <iostream> #include <string> namespace test_space{ int var = 10; } using namespace std; using namespace test_space; int main() { double var = 20.53; cout<<"local var = "<<var<<endl; cout<<"test_space::var = "<<::var; return 0; } |
Вывод данных:
1 2 |
local var = 20.53 test_space::var = 10 |
В приведенном выше примере мы использовали два оператора после определения пространства имен «test_space». Вот они:
1 2 |
using namespace std; using namespace test_space; |
Первый оператор использует объявление для доступа к пространству имен «std», которое является предопределенным стандартным пространством имен в библиотеке C++. Это пространство имен используется для доступа к различным функциям, таким как cin, cout и т.д.
Второй оператор используется для включения пространства имен «test_space» в программу.
В функции main мы видим, что таким функциям, как cout и переменная var, не обязательно должно предшествовать имя пространства имен. Мы можем напрямую обратиться к ним. Но поскольку имя var конфликтует с локальной переменной в основной функции, мы обращаемся к ней с помощью оператора разрешения области видимости (::), поскольку пространства имен также всегда имеют глобальную область видимости.
Вложенные пространства имен
C++ также позволяет иметь вложенные пространства имен, т.е. пространство имен, определенное внутри другого пространства имен.
Общий синтаксис вложенных пространств имен следующий:
1 2 3 4 5 6 |
namespace ns1{ ns1_code; namespace ns2{ ns2_code; } } |
Если нам нужно получить доступ к ns2_code, то мы можем получить к нему доступ следующим образом:
1 |
ns1::ns2::ns2_code; |
Давайте продемонстрируем вложенные пространства имен, используя следующий пример кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
#include <iostream> #include <string> namespace first{ int var = 10; namespace second{ int secVar = 20; } } using namespace std; using namespace first; using namespace first::second; int main() { double var = 20.53; cout<<"local var = "<<var<<endl; cout<<"first::var = "<<::var<<endl; cout<<"second::var = "<<secVar; return 0; } |
Вывод данных:
1 2 3 |
local var = 20.53 first::var = 10 second::var = 20 |
Мы использовали вложенные пространства имен в приведенной выше программе. Обратите внимание на способ использования директивы using для доступа к пространствам имен. Недостаточно один раз сослаться только на самое внутреннее пространство имен. Если нам нужен код из самого внешнего пространства имен, нам нужно указать его отдельно.
Мы можем использовать другое имя для пространств имен, известное как «псевдоним». Это особенно полезно при использовании вложенных пространств имен, когда степень вложенности высока.
Мы можем продемонстрировать псевдоним для пространства имен, изменив приведенный выше пример:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
#include <iostream> #include <string> namespace first{ int var = 10; namespace second{ int secVar = 20; } } using namespace std; using namespace first; namespace nested = first::second; int main() { double var = 20.53; cout<<"local var = "<<var<<endl; cout<<"first::var = "<<::var<<endl; cout<<"second::var = "<<nested::secVar; return 0; } |
Вывод данных:
1 2 3 |
local var = 20.53 first::var = 10 second::var = 20 |
Обратите внимание на вложенный псевдоним, определенный для пространства имен first::second. Как только псевдоним определен, мы можем обратиться к пространству имен, используя псевдоним.
Внешние пространства имен
Иногда, когда у нас слишком много пространств имен для использования в нашем приложении, мы можем захотеть поместить все пространства имен в отдельный файл. Это можно легко сделать. Когда пространства имен находятся в отдельном файле, мы просто включаем этот файл в нашу программу, а затем напрямую используем пространства имен и его содержимое в нашей программе.
Например, у нас есть файл с именем ns.h, который содержит следующее пространство имен:
1 2 3 4 |
//ns.h namespace first{ int var = 25; } |
Теперь в нашей программе мы можем использовать пространство имен «first» следующим образом:
1 2 3 4 5 6 7 |
#include<iostream> #include “ns.h” using namespace std; int main() { cout<<first::var; } |
Поэтому, как только мы включаем файл, содержащий пространства имен, в нашу программу, мы можем использовать пространства имен, как если бы они были объявлены глобально в той же программе.
Смежные пространства имен
C++ также позволяет нам определять то, что называется непрерывными пространствами имен. Непрерывные пространства имен — это пространства имен, которые определены более одного раза, имея одно и то же имя. На самом деле это не отдельные пространства имен, а расширения одного и того же пространства имен.
Непрерывные пространства имен очевидны в приведенном ниже примере:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
#include <iostream> #include <string>. namespace first{ int var = 10; } namespace first{ namespace second{ int secVar = 20; } } using namespace std; using namespace first; namespace nested = first::second; int main() { double var = 20.53; cout<<"local var = "<<var<<endl; cout<<"first::var = "<<::var<<endl; cout<<"second::var = "<<nested::secVar; return 0; } |
Вывод данных:
1 2 3 |
local var = 20.53 first::var = 10 second::var = 20 |
Обратите внимание, что в приведенном выше примере мы дважды определили одно и то же пространство имен. В первом определении у нас есть переменная с именем var. В то время как во втором объявлении у нас определено другое пространство имен.
В основной функции мы получили доступ как к членам внешнего, так и к внутреннего пространства имен, и обратите внимание, что к членам легко получить доступ.
Это пример смежных пространств имен, которые иногда также называют «прерывистыми пространствами имен» (discontinuous namespaces). Их определения кажутся отдельными, но на самом деле они представляют собой непрерывные пространства имен.
Итог
На этом мы подошли к концу данной статьи по пространствам имен в C++. Пространства имен позволяют нам разделить наш код на разные пространства, чтобы у нас была ясность при его чтении, а также при использовании его членов.
В нашей следующие статье вы узнаете об операции ввода-вывода файла и функции указателя файла в C++.
С Уважением, МониторБанк