Jak prawidłowo używać przestrzeni nazw w C++?

Pochodzę z tła Javy, gdzie używane są pakiety, a nie przestrzenie nazw. Jestem przyzwyczajony do umieszczania klas, które współpracują ze sobą, tworząc kompletny obiekt w Pakiety, a następnie używam ich później z tego pakietu. Ale teraz pracuję w C++.

Jak używać przestrzeni nazw w C++? Czy tworzysz pojedynczą przestrzeń nazw dla całej aplikacji, czy tworzysz przestrzenie nazw dla głównych komponentów? Jeśli tak, to jak tworzyć obiekty z klas w innych przestrzeniach nazw?

Author: Philipp Matthias Schäfer, 2008-09-03

15 answers

Przestrzenie nazw są zasadniczo pakietami. Mogą być używane w ten sposób:

namespace MyNamespace
{
  class MyClass
  {
  };
}

Następnie w kodzie:

MyNamespace::MyClass* pClass = new MyNamespace::MyClass();
Mam nadzieję, że to pomoże.

Lub, jeśli chcesz zawsze używać określonej przestrzeni nazw, możesz to zrobić:

using namespace MyNamespace;

MyClass* pClass = new MyClass();

Edit: zgodnie z tym, co powiedział bernhardrusch , zazwyczaj nie używam składni "using namespace x", Zwykle jawnie określam przestrzeń nazw podczas tworzenia instancji moich obiektów (tj. pierwszy przykład, który pokazałem).

I jak prosiłeś poniżej możesz użyć dowolnej liczby przestrzeni nazw.

 160
Author: Mark Ingram,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 10:31:31

Aby uniknąć mówienia wszystkiego Mark Ingram powiedział już małą wskazówkę na używanie przestrzeni nazw:

Unikaj dyrektywy "using namespace" w plikach nagłówkowych-otwiera to przestrzeń nazw dla wszystkich części programu, które importują ten plik nagłówkowy. W plikach implementacyjnych (*.cpp) normalnie nie jest to duży problem-choć wolę używać dyrektywy "using namespace" na poziomie funkcji.

Myślę, że przestrzenie nazw są najczęściej używane, aby uniknąć konfliktów nazewnictwa - niekoniecznie do organizowania struktura kodu. Organizowałbym Programy C++ głównie z plikami nagłówkowymi / strukturą plików.

Czasami przestrzenie nazw są używane w większych projektach C++ do ukrywania szczegółów implementacji.

Uwaga dodatkowa do dyrektywy używającej: Niektórzy wolą używać "using" tylko dla pojedynczych elementów:

using std::cout;  
using std::endl;
 112
Author: bernhardrusch,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-03-11 15:51:48

Vincent Robert ma rację w komentarzu Jak prawidłowo używać przestrzeni nazw w C++?.

Używanie przestrzeni nazw

Przestrzenie nazw są używane co najmniej w celu uniknięcia kolizji nazw. W języku Java jest to wymuszane przez " org.idiom domain " (bo zakłada się, że nie będzie się używać niczego innego niż własna nazwa domeny).

W C++, możesz nadać przestrzeń nazw dla całego kodu w Twoim module. Na przykład dla modułu MyModule.dll, możesz podać jego kod przestrzeń nazw MyModule. Widziałem gdzie indziej kogoś używającego MyCompany:: MyProject:: MyModule. To chyba przesada, ale w sumie wydaje mi się to słuszne.

Using "using"

Używanie powinno być używane z dużą ostrożnością, ponieważ skutecznie importuje jeden (lub wszystkie) symbole z przestrzeni nazw do bieżącej przestrzeni nazw.

To jest złe robić to w pliku nagłówkowym, ponieważ twój nagłówek zanieczyści wszystkie źródła łącznie z nim (przypomina mi to makra...), a nawet w pliku źródłowym, zły styl poza zakresem funkcji, ponieważ zaimportuje ona w zasięgu globalnym symbole z przestrzeni nazw.

Najbezpieczniejszym sposobem użycia "using" jest zaimportowanie wybranych symboli:

void doSomething()
{
   using std::string ; // string is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   std::cout << a << std::endl ;
}

void doSomethingElse()
{
   using namespace std ; // everything from std is now "imported", at least,
                       // until the end of the function
   string a("Hello World!") ;
   cout << a << endl ;
}

Zobaczysz wiele "using namespace std;" w samouczku lub przykładowych kodach. Powodem jest zmniejszenie liczby symboli, aby ułatwić czytanie, a nie dlatego, że jest to dobry pomysł.

"using namespace std ;" jest zniechęcony przez Scotta Meyersa (nie pamiętam dokładnie, która książka, ale mogę ją znaleźć, jeśli konieczne).

Skład Przestrzeni Nazw

Przestrzenie nazw są czymś więcej niż pakietami. Inny przykład można znaleźć w Bjarne Stroustrup ' s "the C++ Programming Language".

W" Special Edition", w 8.2.8 Namespace Composition, opisuje, jak można połączyć dwie przestrzenie nazw AAA i BBB w inną o nazwie CCC. W ten sposób CCC staje się aliasem zarówno dla AAA jak i BBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

namespace CCC
{
   using namespace AAA ;
   using namespace BBB ;
}

void doSomethingAgain()
{
   CCC::doSomething() ;
   CCC::doSomethingElse() ;
}

Możesz nawet zaimportować wybrane symbole z różnych przestrzeni nazw, aby stworzyć własne interfejs przestrzeni nazw. Jeszcze nie znalazłem praktycznego zastosowania tego, ale teoretycznie jest to fajne.

 76
Author: paercebal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-08-07 07:42:03

Nie widziałem żadnej wzmianki o tym w innych odpowiedziach, więc oto moje 2 centy kanadyjskie:

W temacie" Używanie przestrzeni nazw "użytecznym poleceniem jest alias przestrzeni nazw, pozwalający na "zmianę nazwy" przestrzeni nazw, zwykle w celu nadania jej krótszej nazwy. Na przykład zamiast:

Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::TheClassName foo;
Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally::AnotherClassName bar;

Możesz napisać:

namespace Shorter = Some::Impossibly::Annoyingly::Long:Name::For::Namespace::Finally;
Shorter::TheClassName foo;
Shorter::AnotherClassName bar;
 70
Author: Éric Malenfant,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-10-21 13:19:01

Nie słuchaj wszystkich ludzi, którzy mówią ci, że przestrzenie nazw to tylko przestrzenie nazw.

Są ważne, ponieważ kompilator uważa, że stosują zasadę interfejsu. Zasadniczo można to wyjaśnić za pomocą przykładu:

namespace ns {

class A
{
};

void print(A a)
{
}

}

Jeśli chcesz wydrukować obiekt A, kod będzie taki:

ns::A a;
print(a);

Zauważ, że nie wspominaliśmy wprost o przestrzeni nazw podczas wywoływania funkcji. Jest to zasada interfejsu: C++ rozważ funkcję przyjmującą Typ jako argument jako część interfejsu dla tego typu, więc nie ma potrzeby określania przestrzeni nazw, ponieważ parametr już implikuje przestrzeń nazw.

Dlaczego ta zasada jest ważna? Wyobraź sobie, że autor klasy A nie dostarczył funkcji print () dla tej klasy. Będziesz musiał sam go zapewnić. Ponieważ jesteś dobrym programistą, zdefiniujesz tę funkcję we własnej przestrzeni nazw, a może w globalnej przestrzeni nazw.
namespace ns {

class A
{
};

}

void print(A a)
{
}

I twój kod może zacząć wywoływać print(a) działaj tam, gdzie chcesz. Wyobraź sobie, że po latach autor decyduje się dostarczyć funkcję print (), lepszą niż Twoja, ponieważ zna wewnętrzne elementy swojej klasy i może stworzyć lepszą wersję niż Twoja.

Wtedy autorzy C++ zdecydowali, że jego wersja funkcji print () powinna być używana zamiast tej podanej w innej przestrzeni nazw, aby respektować zasadę interfejsu. I że ta "aktualizacja" funkcji print() powinna być jak najprostsza, co oznacza, że nie trzeba zmieniać każde wywołanie funkcji print (). Dlatego "funkcje interfejsu" (funkcja w tej samej przestrzeni nazw co Klasa) mogą być wywoływane bez określania przestrzeni nazw w C++.

I dlatego powinieneś rozważyć przestrzeń nazw C++ jako "interfejs", gdy go używasz i pamiętać o zasadzie interfejsu.

Jeśli chcesz lepiej wyjaśnić to zachowanie, możesz odwołać się do książki Exceptional C++ z Herb Sutter

 53
Author: Vincent Robert,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-10-30 04:57:28

Większe projekty C++, które widziałem rzadko używały więcej niż jednej przestrzeni nazw (np. biblioteki boost).

W rzeczywistości boost wykorzystuje mnóstwo przestrzeni nazw, zazwyczaj każda część boost ma swoją własną przestrzeń nazw dla wewnętrznego działania, a następnie może umieścić tylko publiczny interfejs w przestrzeni nazw najwyższego poziomu boost.

Osobiście uważam, że im większa jest baza kodu, tym ważniejsze stają się przestrzenie nazw, nawet w obrębie jednej aplikacji (lub biblioteki). W pracy stawiamy każdy moduł naszego aplikacja we własnej przestrzeni nazw.

Innym użyciem (nie zamierzonym kalamburem) przestrzeni nazw, których często używam, jest anonimowa przestrzeń nazw:

namespace {
  const int CONSTANT = 42;
}

To jest w zasadzie to samo co:

static const int CONSTANT = 42;

Używanie anonimowej przestrzeni nazw (zamiast statycznej) jest jednak zalecanym sposobem, aby kod i dane były widoczne tylko w bieżącej jednostce kompilacji w C++.

 36
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-07 00:38:54

Zauważ również, że możesz dodać do przestrzeni nazw. To jest jaśniejsze z przykładem, chodzi mi o to, że możesz mieć:

namespace MyNamespace
{
    double square(double x) { return x * x; }
}

W pliku square.h i

namespace MyNamespace
{
    double cube(double x) { return x * x * x; }
}

W pliku cube.h. Definiuje to pojedynczą przestrzeń nazw MyNamespace (to znaczy, można zdefiniować pojedynczą przestrzeń nazw dla wielu plików).

 18
Author: OysterD,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-07-23 21:24:09

W Języku Java:

package somepackage;
class SomeClass {}

W C++:

namespace somenamespace {
    class SomeClass {}
}

I używając ich, Java:

import somepackage;

I C++:

using namespace somenamespace;

Również pełne nazwy to " somepackge.SomeClass "dla Javy i" somenamespace:: SomeClass " dla C++. Korzystając z tych konwencji, możesz organizować się tak, jak w Javie, w tym tworzyć pasujące nazwy folderów dla przestrzeni nazw. Nie ma jednak wymagań dotyczących folderów->pakiet i plik->Klasa, więc możesz nazywać swoje foldery i klasy niezależnie od pakietów i przestrzenie nazw.

 11
Author: Staale,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 13:09:44

Możesz także zawierać " using namespace ..."wewnątrz funkcji na przykład:

void test(const std::string& s) {
    using namespace std;
    cout << s;
}
 5
Author: Shadow2531,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 14:59:01

@marius

Tak, możesz używać kilku przestrzeni nazw na raz, np:

using namespace boost;   
using namespace std;  

shared_ptr<int> p(new int(1));   // shared_ptr belongs to boost   
cout << "cout belongs to std::" << endl;   // cout and endl are in std
[[1]} [Luty 2014 -- (Czy to naprawdę tak długo?): Ten konkretny przykład jest teraz dwuznaczny, jak wskazuje Joey poniżej. Boost i std:: teraz każdy ma shared_ptr.]
 5
Author: Adam Hollidge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-05-23 11:54:50

Ogólnie rzecz biorąc, tworzę przestrzeń nazw dla ciała kodu, jeśli wierzę, że może istnieć konflikt nazw funkcji lub typu z innymi bibliotekami. Pomaga również znakować kod, ala boost:: .

 3
Author: Adam Hollidge,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 13:00:19

Wolę używać najwyższego poziomu przestrzeni nazw dla aplikacji i podrzędnych przestrzeni nazw Dla komponentów.

Sposób używania klas z innych przestrzeni nazw jest zaskakująco bardzo podobny do sposobu w Javie. Możesz użyć "użyj przestrzeni nazw", która jest podobna do instrukcji "Importuj pakiet" , np. użyj std. Albo podajesz pakiet jako prefiks klasy oddzielonej "::", np. std::string. Jest to podobne do "java.lang.String " w języku Java.

 3
Author: dmeister,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 13:00:50

Zauważ, że przestrzeń nazw w C++ jest tak naprawdę tylko przestrzenią nazw. Nie zapewniają one żadnej enkapsulacji, jaką Pakiety wykonują w Javie, więc prawdopodobnie nie będziesz ich używał tak często.

 3
Author: Kristopher Johnson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 13:19:09

Używałem przestrzeni nazw C++ tak samo jak w C#, perlu itp. To tylko semantyczna separacja symboli między standardowymi bibliotekami, innymi rzeczami i moim własnym kodem. Chciałbym umieścić własną aplikację w jednej przestrzeni nazw, a następnie komponent biblioteki wielokrotnego użytku w innej przestrzeni nazw do oddzielenia.

 2
Author: spoulson,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-03 13:38:25

Inną różnicą między Javą A C++ jest to, że w C++ hierarchia przestrzeni nazw nie musi mach układu systemu plików. Tak więc zazwyczaj umieszczam całą bibliotekę wielokrotnego użytku w jednej przestrzeni nazw, a podsystemy w bibliotece w podkatalogach:

#include "lib/module1.h"
#include "lib/module2.h"

lib::class1 *v = new lib::class1();

Umieściłbym podsystemy w zagnieżdżonych przestrzeniach nazw tylko wtedy, gdy istnieje możliwość konfliktu nazw.

 2
Author: KeithB,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-03-15 19:54:07