Prawdopodobnie duplikat, ale niełatwy do wyszukania ...
Biorąc pod uwagę nagłówek taki jak:
namespace ns1
{
class MyClass
{
void method();
};
}
Widziałem method()
zdefiniowane na kilka sposobów w pliku .cpp:
Wersja 1:
namespace ns1
{
void MyClass::method()
{
...
}
}
Wersja 2:
using namespace ns1;
void MyClass::method()
{
...
}
Wersja 3:
void ns1::MyClass::method()
{
...
}
Czy istnieje „właściwy” sposób, aby to zrobić? Czy któryś z tych „błędów” nie oznacza tego samego?
c++
coding-style
namespaces
Mr. Boy
źródło
źródło
Odpowiedzi:
Wersja 2 jest niejasna i niełatwa do zrozumienia, ponieważ nie wiesz, do której przestrzeni nazw
MyClass
należy i jest po prostu nielogiczna (funkcja klasy nie znajduje się w tej samej przestrzeni nazw?)Wersja 1 ma rację, ponieważ pokazuje, że w przestrzeni nazw definiujesz funkcję.
Wersja 3 jest słuszna również dlatego, że użyłeś
::
operatora rozpoznawania zakresu do odniesienia się doMyClass::method ()
w przestrzeni nazwns1
. Wolę wersję 3.Zobacz przestrzenie nazw (C ++) . To najlepszy sposób, aby to zrobić.
źródło
namespace N {struct X { void f(); }; X operator==( X const &, X const & ); }
, teraz w pliku cpp z instrukcją using możesz zdefiniować funkcję składową jakovoid X::f() {}
, ale jeśli zdefiniujeszX operator==(X const&, X const&)
, zdefiniujesz inny operator niż ten zdefiniowane w nagłówku (będziesz musiał użyć 1 lub 3 dla wolnej funkcji tam).Pięć lat później pomyślałem, że wspomnę o tym, co zarówno ładnie wygląda, jak i nie jest złe
źródło
Używam wersji 4 (poniżej), ponieważ łączy ona większość zalet wersji 1 (zwięzłość definicji resoekcyjnej) i wersji 3 (maksymalnie wyraźna). Główną wadą jest to, że ludzie nie są do tego przyzwyczajeni, ale ponieważ uważam, że jest to technicznie lepsze od alternatyw, nie mam nic przeciwko.
Wersja 4: użyj pełnej kwalifikacji przy użyciu aliasów przestrzeni nazw:
W moim świecie często używam aliasów przestrzeni nazw, ponieważ wszystko jest jawnie kwalifikowane - chyba że nie może (np. Nazwy zmiennych) lub jest to znany punkt dostosowywania (np. Swap () w szablonie funkcji).
źródło
outer
iinner
zdefiniowane jako nazw już w innych plikach nagłówkowych?Wersja 3 sprawia, że powiązanie między klasą a przestrzenią nazw jest bardzo wyraźne, kosztem częstszego pisania. Wersja 1 unika tego, ale przechwytuje powiązanie z blokiem. Wersja 2 ma tendencję do ukrywania tego, więc unikałbym tego.
źródło
Przewodnik Google po stylu C ++ dyktuje wersję 1, ale bez wcięć.
źródło
Wybieram Num.3 (czyli wersję pełną). Jest to bardziej typowe, ale intencja jest dokładna dla Ciebie i dla kompilatora. Problem, który opublikowałeś w obecnej postaci, jest w rzeczywistości prostszy niż w prawdziwym świecie. W prawdziwym świecie istnieją inne zakresy definicji, a nie tylko członkowie klas. Twoje definicje nie są zbyt skomplikowane w przypadku samych klas - ponieważ ich zakres nigdy nie jest ponownie otwierany (w przeciwieństwie do przestrzeni nazw, zasięgu globalnego itp.).
Num.1 może się to nie powieść w przypadku zakresów innych niż klasy - wszystko, co można ponownie otworzyć. Możesz więc zadeklarować nową funkcję w przestrzeni nazw, używając tego podejścia, lub twoje inline mogą zostać zastąpione przez ODR. Będzie to potrzebne w przypadku niektórych definicji (w szczególności specjalizacji szablonów).
Num.2 Jest to bardzo delikatne, szczególnie w dużych bazach kodu - gdy zmieniają się nagłówki i zależności, twój program nie skompiluje się.
Num.3 Jest to idealne rozwiązanie, ale dużo do pisania - co swoją intencją jest, aby zdefiniować coś . To robi dokładnie to, a kompilator włącza się, aby upewnić się, że nie popełniłeś błędu, definicja nie jest niezgodna z jej deklaracją itp.
źródło
Okazuje się, że to nie tylko „kwestia stylu kodowania”. Num. 2 prowadzi do błędu łączenia podczas definiowania i inicjalizacji zmiennej zadeklarowanej extern w pliku nagłówkowym. Spójrz na przykład w moim pytaniu. Definicja stałej w przestrzeni nazw w pliku cpp
źródło
Wszystkie drogi są właściwe, a każda ma swoje zalety i wady.
W wersji 1 masz tę zaletę, że nie musisz pisać przestrzeni nazw przed każdą funkcją. Wadą jest to, że otrzymasz nudną identyfikację, szczególnie jeśli masz więcej niż jeden poziom przestrzeni nazw.
W wersji 2 sprawiasz, że kod jest bardziej przejrzysty, ale jeśli masz więcej niż jedną przestrzeń nazw implementowaną w CPP, jedna może mieć bezpośredni dostęp do funkcji i zmiennych drugiej, czyniąc twoją przestrzeń nazw bezużyteczną (dla tego pliku cpp).
W wersji 3 będziesz musiał wpisać więcej, a linie funkcji mogą być większe niż ekran, co jest niekorzystne dla efektów projektowych.
Jest też inny sposób, w jaki niektórzy go używają. Jest podobny do pierwszej wersji, ale bez problemów z identyfikacją.
To jest tak:
Do Ciebie należy wybór, który jest lepszy w każdej sytuacji =]
źródło
#ifdef
klauzuli.#define OPEN_NS(X)
myślę, że jest to trochę przydatne, ale nie do końca ... Nie sprzeciwiam się makrom, ale wydaje się to trochę OTT. Myślę, że podejście Dietmara Kühla jest lepsze w przypadku zagnieżdżonych przestrzeni nazw.