Frage

Ich komme aus einem Java-Hintergrund, wo Pakete verwendet werden, keine Namespaces.Ich bin es gewohnt, Klassen, die zusammenarbeiten, um ein vollständiges Objekt zu bilden, in Paketen zusammenzufassen 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?

War es hilfreich?

Lösung

Namespaces sind im Wesentlichen Pakete.Sie können wie folgt verwendet werden:

namespace MyNamespace
{
  class MyClass
  {
  };
}

Dann im Code:

MyNamespace::MyClass* pClass = new MyNamespace::MyClass();

Hoffentlich hilft das.

Wenn Sie immer einen bestimmten Namespace verwenden möchten, können Sie auch Folgendes tun:

using namespace MyNamespace;

MyClass* pClass = new MyClass();

Bearbeiten: Nach was bernhardrusch Ich habe gesagt, dass ich die Syntax „Namensraumdas erste Beispiel, das ich gezeigt habe).

Und wie du gefragt hast unten, können Sie beliebig viele Namespaces verwenden.

Andere Tipps

Um nicht alles zu sagen, hat Mark Ingram bereits einen kleinen Tipp zur Verwendung von Namespaces gesagt:

Vermeiden Sie die Direktive „using namespace“ in Header-Dateien – diese öffnet den Namespace für alle Teile des Programms, die diese Header-Datei importieren.In Implementierungsdateien (*.cpp) ist dies normalerweise kein großes Problem – ich bevorzuge jedoch die Verwendung der Direktive „using namespace“ auf Funktionsebene.

Ich denke, Namespaces werden hauptsächlich 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 Namespaces in größeren C++-Projekten verwendet, um Implementierungsdetails zu verbergen.

Zusätzlicher Hinweis zur using-Direktive:Manche Leute bevorzugen die Verwendung von „using“ nur für einzelne Elemente:

using std::cout;  
using std::endl;

Vincent Robert hat mit seinem Kommentar Recht 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 davon ausgegangen wird, dass man nichts anderes als seinen/ihren eigenen Domänennamen verwendet).

In C++ könnten Sie dem gesamten Code in Ihrem Modul einen Namensraum zuweisen.Beispielsweise könnten Sie für ein Modul „MyModule.dll“ dem Code den Namensraum „MyModule“ geben.Ich habe an anderer Stelle jemanden gesehen, der MyCompany::MyProject::MyModule verwendet.Ich denke, das ist übertrieben, aber alles in allem scheint es mir richtig zu sein.

Verwendung von „using“

Using sollte mit großer Vorsicht verwendet werden, da es effektiv ein (oder alle) Symbole aus einem Namespace in Ihren aktuellen Namespace importiert.

Dies in einer Header-Datei zu tun ist böse, da Ihr Header jede Quelle einschließlich dieser verunreinigt (es erinnert mich an Makros ...), und selbst in einer Quelldatei ist der Stil außerhalb eines Funktionsbereichs schlecht, da er im globalen Bereich importiert wird die Symbole aus dem Namensraum.

Der sicherste Weg, „using“ zu verwenden, ist der Import ausgewählter Symbole:

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 ;
}

Sie werden viel "mit dem Namespace STD verwenden" sehen; In Tutorial oder Beispielcodes.Der Grund liegt darin, die Anzahl der Symbole zu reduzieren, um das Lesen zu erleichtern, und nicht, weil es eine gute Idee wäre.

"Verwenden von Namespace STD;" wird von Scott Meyers entmutigt (ich erinnere mich nicht genau an welches Buch, aber ich kann es bei Bedarf finden).

Zusammensetzung des Namensraums

Namespaces sind mehr als Pakete.Ein weiteres Beispiel findet sich in Bjarne Stroustrups „The C++ Programming Language“.

In der „Special Edition“, bei 8.2.8 Namensraumzusammensetzung, beschreibt er, wie man zwei Namensräume AAA und BBB zu einem anderen Namensraum namens CCC zusammenführen kann.Somit wird CCC zu einem Alias ​​sowohl für AAA als auch für BBB:

namespace AAA
{
   void doSomething() ;
}

namespace BBB
{
   void doSomethingElse() ;
}

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

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

Sie können sogar ausgewählte Symbole aus verschiedenen Namespaces importieren, um Ihre eigene benutzerdefinierte Namespace-Schnittstelle zu erstellen.Ich habe noch keinen praktischen Nutzen dafür gefunden, aber theoretisch ist es cool.

Ich habe in den anderen Antworten keine Erwähnung davon gesehen, daher hier meine 2 kanadischen Cent:

Zum Thema „Namespace verwenden“ ist der Namespace-Alias ​​eine nützliche Anweisung, mit der Sie einen Namespace „umbenennen“ können, normalerweise um ihm einen kürzeren Namen zu geben.Zum Beispiel statt:

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

Du kannst schreiben:

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

Hören Sie nicht auf alle Leute, die Ihnen sagen, dass Namespaces nur Namespaces sind.

Sie sind wichtig, weil sie vom Compiler als Anwendung des Schnittstellenprinzips angesehen werden.Im Grunde kann man es an einem Beispiel erklären:

namespace ns {

class A
{
};

void print(A a)
{
}

}

Wenn Sie ein A-Objekt drucken möchten, wäre der Code dieser:

ns::A a;
print(a);

Beachten Sie, dass wir den Namespace beim Aufruf der Funktion nicht explizit erwähnt haben.Das ist das Schnittstellenprinzip:C++ betrachtet eine Funktion, die einen Typ als Argument verwendet, als Teil der Schnittstelle für diesen Typ. Daher muss der Namespace nicht angegeben werden, da der Parameter den Namespace bereits impliziert.

Warum ist dieses Prinzip nun wichtig?Stellen Sie sich vor, dass der Autor der Klasse A für diese Klasse keine print()-Funktion bereitgestellt hat.Sie müssen selbst für eines sorgen.Da Sie ein guter Programmierer sind, definieren Sie diese Funktion in Ihrem eigenen Namensraum oder vielleicht im globalen Namensraum.

namespace ns {

class A
{
};

}

void print(A a)
{
}

Und Ihr Code kann mit dem Aufruf der Funktion print(a) beginnen, 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, weil er die Interna seiner Klasse kennt und eine bessere Version als Ihre erstellen kann.

Dann beschlossen die C++-Autoren, dass seine Version der print()-Funktion anstelle der in einem anderen Namespace bereitgestellten Version 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 in C++ „Schnittstellenfunktionen“ (Funktionen im gleichen Namensraum wie eine Klasse) ohne Angabe des Namensraums aufgerufen werden.

Und deshalb sollten Sie einen C++-Namespace als „Schnittstelle“ betrachten, wenn Sie einen solchen verwenden, und das Schnittstellenprinzip im Auge behalten.

Wenn Sie eine bessere Erklärung dieses Verhaltens wünschen, können Sie auf das Buch zurückgreifen Außergewöhnliches C++ von Herb Sutter

Größere C++-Projekte, die ich gesehen habe, verwendeten kaum mehr als einen Namespace (z. B.Boost-Bibliothek).

Tatsächlich verwendet Boost unzählige Namespaces. Normalerweise hat jeder Teil von Boost seinen eigenen Namespace für das Innenleben und fügt dann möglicherweise nur die öffentliche Schnittstelle in den Namespace der obersten Ebene von Boost ein.

Persönlich denke ich, dass Namespaces umso wichtiger werden, je größer eine Codebasis wird, selbst innerhalb einer einzelnen Anwendung (oder Bibliothek).Bei der Arbeit platzieren wir jedes Modul unserer Anwendung in einem eigenen Namensraum.

Eine andere Verwendung (kein Wortspiel beabsichtigt) von Namespaces, die ich häufig verwende, ist der anonyme Namespace:

namespace {
  const int CONSTANT = 42;
}

Das ist im Grunde dasselbe wie:

static const int CONSTANT = 42;

Die Verwendung eines anonymen Namespace (anstelle eines statischen) ist jedoch die empfohlene Methode, damit Code und Daten nur innerhalb der aktuellen Kompilierungseinheit in C++ sichtbar sind.

Beachten Sie außerdem, dass Sie einem Namespace etwas hinzufügen können.Anhand eines Beispiels wird das deutlicher. Ich meine, Sie können Folgendes haben:

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

in einer Datei square.h, Und

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

in einer Datei cube.h.Dies definiert einen einzelnen Namespace MyNamespace (das heißt, Sie können einen einzelnen Namespace über mehrere Dateien hinweg definieren).

In Java:

package somepackage;
class SomeClass {}

In C++:

namespace somenamespace {
    class SomeClass {}
}

Und mit ihnen, Java:

import somepackage;

Und C++:

using namespace somenamespace;

Außerdem lauten die vollständigen Namen „somepackge.SomeClass“ für Java und „somenamespace::SomeClass“ für C++.Mithilfe dieser Konventionen können Sie wie in Java gewohnt organisieren, einschließlich der Erstellung übereinstimmender Ordnernamen für Namespaces.Die Ordner->Paket- und Datei->Klasse-Anforderungen sind jedoch nicht vorhanden, sodass Sie Ihre Ordner und Klassen unabhängig von Paketen und Namespaces benennen können.

Sie können auch „using namespace ...“ in einer Funktion enthalten, zum Beispiel:

void test(const std::string& s) {
    using namespace std;
    cout << s;
}

@Marius

Ja, Sie können mehrere Namespaces gleichzeitig verwenden, z. B.:

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

[Februar.2014 – (Ist das wirklich schon so lange her?):Dieses spezielle Beispiel ist nun mehrdeutig, wie Joey weiter unten betont.Boost und Standard::jetzt hat jeder einen shared_ptr.]

Im Allgemeinen erstelle ich einen Namespace für einen Codekörper, wenn ich glaube, dass möglicherweise Funktions- oder Typnamenkonflikte mit anderen Bibliotheken vorliegen könnten.Es hilft auch, den Markencode zu erstellen Schub:: .

Ich bevorzuge die Verwendung eines Top-Level-Namespaces für die Anwendung und Sub-Namespaces für die Komponenten.

Die Art und Weise, wie Sie Klassen aus anderen Namespaces verwenden können, ist überraschenderweise der Art und Weise in Java sehr ähnlich.Sie können entweder „use NAMESPACE“ verwenden, was einer „import PACKAGE“-Anweisung ähnelt, z. B.Verwenden Sie Standard.Oder Sie geben das Paket als Präfix der Klasse getrennt durch „::“ an, z.B.std::string.Dies ähnelt „java.lang.String“ in Java.

Beachten Sie, dass ein Namespace in C++ eigentlich nur ein Namespace ist.Sie bieten nicht die Kapselung, die Pakete in Java bieten, daher werden Sie sie wahrscheinlich nicht so häufig verwenden.

Ich habe C++-Namespaces auf die gleiche Weise verwendet wie in C#, Perl usw.Es handelt sich lediglich um eine semantische Trennung von Symbolen zwischen Standardbibliotheksinhalten, Inhalten 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.

Ein weiterer Unterschied zwischen Java und C++ besteht darin, dass in C++ die Namespace-Hierarchie nicht das Dateisystem-Layout anpassen muss.Daher neige ich dazu, eine gesamte wiederverwendbare Bibliothek in einem einzigen Namensraum abzulegen und Subsysteme innerhalb der Bibliothek in Unterverzeichnissen:

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

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

Ich würde die Subsysteme nur dann in verschachtelte Namespaces legen, wenn die Möglichkeit eines Namenskonflikts bestünde.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top