Rozważmy parę dwóch plików źródłowych: plik deklaracji interfejsu ( *.h
lub *.hpp
) i plik jego implementacji ( *.cpp
).
Niech *.h
plik będzie podobny do następującego:
namespace MyNamespace {
class MyClass {
public:
int foo();
};
}
Widziałem dwie różne praktyki dotyczące używania przestrzeni nazw w plikach źródłowych:
*.cpp
pokazując praktykę nr 1:
#include "MyClass.h"
using namespace MyNamespace;
int MyClass::foo() { ... }
*.cpp
pokazując praktykę nr 2:
#include "MyClass.h"
namespace MyNamespace {
int MyClass::foo() { ... }
}
Moje pytanie: czy są jakieś różnice między tymi dwiema praktykami i czy jedna jest uważana za lepszą od drugiej?
c++
namespaces
header-files
nickolay
źródło
źródło
int MyNamespace::MyClass::foo() ...
.Odpowiedzi:
Z punktu widzenia czytelności kodu, moim zdaniem prawdopodobnie lepiej jest użyć metody nr 2 z tego powodu:
Jednocześnie może istnieć
using
wiele przestrzeni nazw, a każdy obiekt lub funkcja zapisana poniżej tej linii może należeć do dowolnej z tych przestrzeni nazw (z wyjątkiem konfliktów nazw). Zawijanie całego pliku wnamespace
bloku jest bardziej wyraźne i pozwala zadeklarować nowe funkcje i zmienne, które należą do tej przestrzeni nazw, również w pliku .cppźródło
Najwyraźniejsza jest opcja, której nie pokazałeś:
int MyNamespace::MyClass::foo() { // ... }
Jest również bardzo rozwlekły; za dużo dla większości ludzi. Ponieważ
using namespace
jest to recepta na konflikty nazw, przynajmniej z mojego doświadczenia, i powinno się ich unikać, z wyjątkiem bardzo ograniczonych zakresów i miejsc, generalnie używam twojego # 2.źródło
Tak. # 1 i # 2 to przykłady odpowiednio dyrektywy using i definicji przestrzeni nazw . W tym przypadku są one faktycznie takie same, ale mają inne konsekwencje. Na przykład, jeśli obok wprowadzisz nowy identyfikator
MyClass::foo
, będzie on miał inny zakres:# 1:
using namespace MyNamespace; int x; // defines ::x
# 2:
namespace MyNamespace { int x; // defines MyNamespace::x }
# 1 Zalety: trochę bardziej zwięzły; trudniej przypadkowo wprowadzić coś w
MyNamespace
nieświadomy sposób. Wady: może przypadkowo pobrać istniejące identyfikatory.# 2 Zalety: jaśniejsze, że definicje istniejących identyfikatorów i deklaracje nowych identyfikatorów należą do obu
MyNamespace
. Wady: łatwiej jest nieumyślnie wprowadzić identyfikatory doMyNamespace
.Krytyką obu punktów 1 i 2 jest to, że odnoszą się one do całej przestrzeni nazw, podczas gdy prawdopodobnie zależy Ci tylko na definicji członków
MyNamespace::MyClass
. Jest to uciążliwe i słabo przekazuje zamiar.Możliwą alternatywą dla # 1 jest deklaracja użycia, która zawiera tylko interesujący Cię identyfikator:
#include "MyClass.h" using MyNamespace::MyClass; int MyClass::foo() { ... }
źródło
Chciałbym również dodać, że jeśli z jakiegoś powodu zdecydujesz się zaimplementować specjalizację szablonu w pliku cpp i polegasz tylko na
using namespace
tym, napotkasz następujący problem:// .h file namespace someNameSpace { template<typename T> class Demo { void foo(); }; } // .cpp file using namespace someNameSpace; template<typename T> void Demo<T>::foo(){} // this will produce // error: specialization of 'template<class T> void someNameSpace::Demo<T>::foo()' in different namespace [-fpermissive] template<> void Demo<int>::foo(){}
W przeciwnym razie, jeśli zastosujesz metodę nr 2, będzie dobrze.
źródło
Chciałbym dodać jeszcze jeden sposób, używając deklaracji using :
#include "MyClass.h" using MyNamespace::MyClass; int MyClass::foo() { ... }
W ten sposób oszczędza się wielokrotnego wpisywania nazwy przestrzeni nazw, jeśli klasa ma wiele funkcji
źródło