Tworzenie przestrzeni nazw C ++ w nagłówku i źródle (CPP)

88

Czy jest jakaś różnica między zawijaniem zawartości pliku nagłówka i pliku cpp w przestrzeni nazw lub zawijaniem samej zawartości nagłówka, a następnie użyciem przestrzeni nazw w pliku CPP?

Przez różnicę rozumiem każdy spadek wydajności lub nieco inną semantykę, która może powodować problemy lub cokolwiek, o czym muszę wiedzieć.

Przykład:

// header
namespace X
{
  class Foo
  {
  public:
    void TheFunc();
  };
}

// cpp
namespace X
{
  void Foo::TheFunc()
  {
    return;
  }
}

VS

// header
namespace X
{
  class Foo
  {
  public:
    void TheFunc();
  };
}

// cpp
using namespace X;
{
  void Foo::TheFunc()
  {
    return;
  }
} 

Jeśli nie ma różnicy, jaka jest preferowana forma i dlaczego?

linki77
źródło

Odpowiedzi:

37

Przestrzeń nazw to tylko sposób na modyfikowanie sygnatur funkcji, aby nie powodowały konfliktów. Niektórzy wolą pierwszy sposób, a inni wolą drugą wersję. Obie wersje nie mają żadnego wpływu na wydajność w czasie kompilacji. Zauważ, że przestrzenie nazw są po prostu jednostką czasu kompilacji.

Jedynym problemem, który pojawia się przy używaniu przestrzeni nazw, jest sytuacja, gdy mamy takie same zagnieżdżone nazwy przestrzeni nazw (tj X::X::Foo. ) . Takie postępowanie powoduje większe zamieszanie przy użyciu słów kluczowych lub bez nich.

vprajan
źródło
55

Różnica w „namespace X” do „using namespace X” polega na tym, że w pierwszym przypadku wszelkie nowe deklaracje będą znajdować się pod przestrzenią nazw, podczas gdy w drugim nie.

W twoim przykładzie nie ma nowej deklaracji - więc nie ma różnicy, stąd nie ma preferowanego sposobu.

Roee Gavirel
źródło
To zależy od projektu i stylu. Często istnieje jedna główna przestrzeń nazw dla załadowania plików w module, a drugi styl ma sens.
Nicholas Wilson
8

Nie ma żadnych kar za wydajność, ponieważ wynik mógłby być taki sam, ale umieszczenie twojego Foow przestrzeni nazw niejawnie wprowadza niejednoznaczność w przypadku, gdy masz Foos w różnych przestrzeniach nazw. Rzeczywiście, możesz dostać swój kod fubar. Zalecam unikanie używania usingw tym celu.

I masz bezpański {po using namespace;-)

Michael Krelin - haker
źródło
Nie nazwałbym tego zbłąkanym, ponieważ pasuje do zamknięcia }na samym końcu. Jednak nazwałbym tę parę
aparatów
@blubberdiblub kwestia została edytowana, jeśli zaznaczone oryginalną wersję, to byłoby nazwać to bezpańskie ;-)
Michael Krelin - haker
1

Jeśli skompiluje się również druga, nie powinno być żadnych różnic. Przestrzenie nazw są przetwarzane w czasie kompilacji i nie powinny wpływać na działania w czasie wykonywania.

Ale jeśli chodzi o kwestie projektowe, druga jest okropna. Nawet jeśli się kompiluje (nie jestem pewien), nie ma to żadnego sensu.

holgac
źródło
1
Myślę, że nie kompiluje się, ale nie dlatego, że jest różnica, ale dlatego, że jest zbłąkany {;-)
Michael Krelin - haker 21.11.11
Różnica polega na tym, że Foo :: TheFunc () jest zadeklarowana w globalnej przestrzeni nazw, podczas gdy jest zdefiniowana w przestrzeni nazw X.
bert-jan
1

Foo :: TheFunc () nie znajduje się w poprawnej przestrzeni nazw w przypadku VS. Użyj „void X :: Foo :: TheFunc () {}”, aby zaimplementować funkcję w prawidłowej przestrzeni nazw (X).

bert-jan
źródło
Pytanie jest trochę stare, ale czy wiesz, jakie są tego konsekwencje? tj. czy napotkasz jakiekolwiek problemy ze sposobem, w jaki jego przypadek VS deklaruje funkcje w przestrzeni nazw, ale definiuje je poza nią?
Adam Goodwin
1

W przypadku, gdy zawijasz tylko zawartość .h, musisz pisać używając przestrzeni nazw ... w pliku cpp, w przeciwnym razie za każdym razem pracujesz na prawidłowej przestrzeni nazw. Zwykle pakujesz zarówno pliki .cpp, jak i .h, w przeciwnym razie istnieje ryzyko użycia obiektów z innej przestrzeni nazw, co może powodować wiele problemów.

AlexTheo
źródło
0

Myślę, że właściwym rozwiązaniem jest użycie przestrzeni nazw do określania zakresu.

namespace catagory
{
    enum status
    {
      none,
      active,
      paused
    }
};

void func()
{
    catagory::status status;
    status = category::active;
}
Kjetil Hvalstrand
źródło
0

Jeśli próbujesz używać zmiennych z jednej do drugiej, polecam ich eksternalizację, a następnie zainicjowanie ich w pliku źródłowym w następujący sposób:

// [.hh]
namespace example
{
   extern int a, b, c;
}
// [.cc]
// Include your header, then init the vars:
namespace example
{
   int a, b, c;
}
// Then in the function below, you can init them as what you want: 
void reference
{
    example::a = 0;
}

źródło