Ich komme aus einem Java-Hintergrund, in dem Pakete verwendet werden, keine Namespaces. Ich bin es gewohnt, Klassen, die zusammenarbeiten, um ein vollständiges Objekt zu bilden, in Pakete zu setzen und sie später aus diesem Paket wiederzuverwenden. Aber jetzt arbeite ich in C ++.
Wie verwendet man Namespaces in C ++? Erstellen Sie einen einzelnen Namespace für die gesamte Anwendung oder erstellen Sie Namespaces für die Hauptkomponenten? Wenn ja, wie erstellen Sie Objekte aus Klassen in anderen Namespaces?
quelle
std
, Symbolen den Namespace voranzustellen, als ihnusing
überhaupt zu verwenden. Also schreibe ich immerstd::cout
oderstd::string
jetzt, weil ich sie jetzt so nenne. Ich würde niemals einfach schreibencout
.std
, aber ich persönlich fand dies viel weniger wichtig, wenn Sie mit kleineren Bibliotheken arbeiten. Oft können Sie nur verwendenusing namespace FooBario;
, insbesondere wenn Sie eine beträchtliche Anzahl von Typen aus einer Bibliothek verwenden.using namespace X;
dies in Header-Dateien nach Möglichkeit vermieden werden sollte.mylibrary::endl
meine ganz eigene Newline-Sequenz darzustellen. Ich meine, warum Namen erfinden?Um nicht alles zu sagen, sagte Mark Ingram bereits einen kleinen Tipp für die Verwendung von Namespaces:
Vermeiden Sie die Anweisung "using namespace" in Header-Dateien. Dadurch wird der Namespace für alle Teile des Programms geöffnet, die diese Header-Datei importieren. In Implementierungsdateien (* .cpp) ist dies normalerweise kein großes Problem - obwohl ich es vorziehe, die Direktive "using namespace" auf Funktionsebene zu verwenden.
Ich denke, Namespaces werden meistens verwendet, um Namenskonflikte zu vermeiden - nicht unbedingt, um Ihre Codestruktur zu organisieren. Ich würde C ++ - Programme hauptsächlich mit Header-Dateien / der Dateistruktur organisieren.
Manchmal werden in größeren C ++ - Projekten Namespaces verwendet, um Implementierungsdetails auszublenden.
Zusätzlicher Hinweis zur using-Direktive: Einige Leute bevorzugen die Verwendung von "using" nur für einzelne Elemente:
quelle
using std::cout;
ist eine Verwendung Erklärungusing std::cout, std::endl;
oder sogar ,using std::cout, endl;
.using namespace x
in einem Header zu verwenden, wenn es sich in einem anderen Namespace befindet. Ich würde es im Allgemeinen nicht empfehlen, aber es verschmutzt den globalen Namespace nicht.Vincent Robert hat Recht in seinem Kommentar Wie verwendet man Namespaces in C ++ richtig? .
Namespace verwenden
Namespaces werden zumindest verwendet, um Namenskollisionen zu vermeiden. In Java wird dies durch die Redewendung "org.domain" erzwungen (da angenommen wird, dass man nichts anderes als seinen eigenen Domainnamen verwendet).
In C ++ können Sie dem gesamten Code in Ihrem Modul einen Namespace zuweisen. Für ein Modul MyModule.dll können Sie seinem Code beispielsweise den Namespace MyModule geben. Ich habe anderswo jemanden gesehen, der MyCompany :: MyProject :: MyModule verwendet. Ich denke, das ist übertrieben, aber alles in allem scheint es mir richtig zu sein.
Verwenden von "using"
Die Verwendung sollte mit großer Sorgfalt erfolgen, da ein (oder alle) Symbole aus einem Namespace effektiv in Ihren aktuellen Namespace importiert werden.
Es ist böse, dies in einer Header-Datei zu tun, da Ihr Header jede Quelle einschließlich dieser verschmutzt (es erinnert mich an Makros ...), und selbst in einer Quelldatei einen schlechten Stil außerhalb eines Funktionsbereichs, da er im globalen Bereich importiert wird die Symbole aus dem Namespace.
Die sicherste Möglichkeit, "using" zu verwenden, besteht darin, ausgewählte Symbole zu importieren:
Sie werden eine Menge "using namespace std" sehen. in Tutorial- oder Beispielcodes. Der Grund ist, die Anzahl der Symbole zu reduzieren, um das Lesen zu erleichtern, nicht weil dies eine gute Idee ist.
"using namespace std;" wird von Scott Meyers entmutigt (ich erinnere mich nicht genau, welches Buch, aber ich kann es bei Bedarf finden).
Namespace-Zusammensetzung
Namespaces sind mehr als Pakete. Ein weiteres Beispiel findet sich in Bjarne Stroustrups "The C ++ Programming Language".
In der "Special Edition" unter 8.2.8 Namespace Composition beschreibt er, wie Sie zwei Namespaces AAA und BBB zu einem anderen namens CCC zusammenführen können. Somit wird CCC sowohl für AAA als auch für BBB zu einem Alias:
Sie können sogar ausgewählte Symbole aus verschiedenen Namespaces importieren, um Ihre eigene benutzerdefinierte Namespace-Oberfläche zu erstellen. Ich habe noch keine praktische Anwendung gefunden, aber theoretisch ist es cool.
quelle
Ich habe keine Erwähnung in den anderen Antworten gesehen, also hier sind meine 2 kanadischen Cent:
Eine nützliche Anweisung zum Thema "Verwenden des Namespace" ist der Namespace-Alias, mit dem Sie einen Namespace "umbenennen" können, normalerweise um ihm einen kürzeren Namen zu geben. Zum Beispiel anstelle von:
Du kannst schreiben:
quelle
Hören Sie nicht jedem zu, der Ihnen sagt, dass Namespaces nur Namensräume sind.
Sie sind wichtig, da sie vom Compiler zur Anwendung des Schnittstellenprinzips herangezogen werden. Grundsätzlich kann dies anhand eines Beispiels erklärt werden:
Wenn Sie ein A-Objekt drucken möchten, lautet der Code wie folgt:
Beachten Sie, dass wir den Namespace beim Aufrufen der Funktion nicht explizit erwähnt haben. Dies ist das Schnittstellenprinzip: C ++ betrachtet eine Funktion, die einen Typ als Argument verwendet, als Teil der Schnittstelle für diesen Typ, sodass der Namespace nicht angegeben werden muss, da der Parameter den Namespace bereits impliziert.
Warum ist dieses Prinzip wichtig? Stellen Sie sich vor, der Autor der Klasse A hat für diese Klasse keine print () -Funktion bereitgestellt. Sie müssen selbst eine bereitstellen. Da Sie ein guter Programmierer sind, definieren Sie diese Funktion in Ihrem eigenen Namespace oder möglicherweise im globalen Namespace.
Und Ihr Code kann die Funktion print (a) aufrufen, wo immer Sie möchten. Stellen Sie sich nun vor, dass der Autor Jahre später beschließt, eine print () - Funktion bereitzustellen, die besser ist als Ihre, da er die Interna seiner Klasse kennt und eine bessere Version als Ihre erstellen kann.
Dann entschieden C ++ - Autoren, dass seine Version der Funktion print () anstelle der in einem anderen Namespace bereitgestellten verwendet werden sollte, um das Schnittstellenprinzip zu respektieren. Und dass dieses "Upgrade" der print () - Funktion so einfach wie möglich sein sollte, was bedeutet, dass Sie nicht jeden Aufruf der print () - Funktion ändern müssen. Aus diesem Grund können "Schnittstellenfunktionen" (Funktion im selben Namespace wie eine Klasse) aufgerufen werden, ohne den Namespace in C ++ anzugeben.
Aus diesem Grund sollten Sie einen C ++ - Namespace als "Schnittstelle" betrachten, wenn Sie einen verwenden, und das Schnittstellenprinzip berücksichtigen.
Wenn Sie dieses Verhalten besser erklären möchten, lesen Sie das Buch Exceptional C ++ von Herb Sutter
quelle
Tatsächlich verwendet Boost Tonnen von Namespaces. Normalerweise hat jeder Teil von Boost einen eigenen Namespace für das Innenleben und kann dann nur die öffentliche Schnittstelle in den Namespace-Boost der obersten Ebene einfügen.
Persönlich denke ich, dass je größer eine Codebasis wird, desto wichtiger werden Namespaces, selbst innerhalb einer einzelnen Anwendung (oder Bibliothek). Bei der Arbeit setzen wir jedes Modul unserer Anwendung in einen eigenen Namespace.
Eine andere Verwendung (kein Wortspiel beabsichtigt) von Namespaces, die ich häufig benutze, ist der anonyme Namespace:
Dies ist im Grunde das gleiche wie:
Die Verwendung eines anonymen Namespace (anstelle eines statischen) ist jedoch die empfohlene Methode, damit Code und Daten nur in der aktuellen Kompilierungseinheit in C ++ sichtbar sind.
quelle
const int CONSTANT = 42;
da die Konstante der obersten Ebene in einem Namespace-Bereich bereits eine interne Verknüpfung impliziert. In diesem Fall benötigen Sie also keinen anonymen Namespace.Beachten Sie außerdem, dass Sie einen Namespace hinzufügen können. Dies wird anhand eines Beispiels klarer. Ich meine, Sie können Folgendes haben:
in einer Datei
square.h
undin einer Datei
cube.h
. Dies definiert einen einzelnen NamespaceMyNamespace
( dh Sie können einen einzelnen Namespace für mehrere Dateien definieren).quelle
In Java:
In C ++:
Und mit ihnen Java:
Und C ++:
Außerdem lauten die vollständigen Namen "somepackge.SomeClass" für Java und "somenamespace :: SomeClass" für C ++. Mit diesen Konventionen können Sie organisieren, wie Sie es in Java gewohnt sind, einschließlich der Erstellung übereinstimmender Ordnernamen für Namespaces. Die Anforderungen für Ordner-> Paket- und Datei-> Klassen sind jedoch nicht vorhanden, sodass Sie Ihre Ordner und Klassen unabhängig von Paketen und Namespaces benennen können.
quelle
@ Marius
Ja, Sie können mehrere Namespaces gleichzeitig verwenden, z.
[Feb. 2014 - (War es wirklich so lange her?): Dieses spezielle Beispiel ist jetzt mehrdeutig, wie Joey weiter unten ausführt. Boost und std :: haben jetzt jeweils ein shared_ptr.]
quelle
std
auch der Fall ist. Wenn Sie also versuchen, a zu verwenden, kollidieren dieshared_ptr
Verwendung von Namespacesboost
undstd
Namespacesshared_ptr
.Sie können in einer Funktion auch "using namespace ..." enthalten, zum Beispiel:
quelle
Im Allgemeinen erstelle ich einen Namespace für einen Code, wenn ich glaube, dass möglicherweise Konflikte mit Funktions- oder Typnamen mit anderen Bibliotheken auftreten. Es hilft auch, Code zu brandmarken, ala boost :: .
quelle
Ich bevorzuge die Verwendung eines Namespace der obersten Ebene für die Anwendung und von Sub-Namespaces für die Komponenten.
Die Art und Weise, wie Sie Klassen aus anderen Namespaces verwenden können, ist überraschenderweise der in Java sehr ähnlich. Sie können entweder "use NAMESPACE" verwenden, ähnlich einer "import PACKAGE" -Anweisung, z. B. "std". Oder Sie geben das Paket als Präfix der durch "::" getrennten Klasse an, z. B. std :: string. Dies ähnelt "java.lang.String" in Java.
quelle
Beachten Sie, dass ein Namespace in C ++ wirklich nur ein Namensraum ist. Sie bieten keine der Kapselungen, die Pakete in Java ausführen, sodass Sie sie wahrscheinlich nicht so häufig verwenden.
quelle
Ich habe C ++ - Namespaces genauso verwendet wie in C #, Perl usw. Es ist nur eine semantische Trennung von Symbolen zwischen Standardbibliotheksmaterial, Material von Drittanbietern und meinem eigenen Code. Ich würde meine eigene App in einem Namespace platzieren und dann eine wiederverwendbare Bibliothekskomponente zur Trennung in einem anderen Namespace.
quelle
Ein weiterer Unterschied zwischen Java und C ++ besteht darin, dass in C ++ die Namespace-Hierarchie das Dateisystem-Layout nicht bearbeiten muss. Daher neige ich dazu, eine gesamte wiederverwendbare Bibliothek in einem einzigen Namespace und Subsysteme innerhalb der Bibliothek in Unterverzeichnissen abzulegen:
Ich würde die Subsysteme nur in verschachtelte Namespaces stellen, wenn die Möglichkeit eines Namenskonflikts besteht.
quelle