Ein Namensbereich (engl. namespace) ist ein Mechanismus zum Gruppieren logisch zusammengehöriger Deklarationen. Diese Technik wird vorwiegend bei größeren Projekten eingesetzt, bei denen durch Namensbereiche repräsentierte Module oft Hunderte von Funktionen, Klassen und Templates beinhalten.
Ein Namensbereich ist ein Gültigkeitsbereich für Namen. In verschiedenen Namensbereichen können gleiche Namen verwendet werden, ohne dass es zu Verwechslungen kommt. Die üblichen Regeln für Gültigkeitsbereiche treffen auch für Namensbereiche zu.
Beispiel:
#include <iostream>
#include <string>
namespace name1
{
double f();
int g(int i);
}
namespace name2
{
void h(std::string s);
int number;
}
double name1::f() { /*...*/ }
int name1::g(int i) { /*...*/ }
void name2::h(std::string s)
{
std::cout << s << name1::f() << " "
<< name1::g(number) << std::endl;
{}Anmerkungen:
Der Qualifizierer name2 bei der Implementierung von
h ist notwendig, um festzuhalten, dass die Funktion
h zu name2 gehört und nicht eine globalen
Funktion ist.
Die Variable number braucht nicht qualifiziert zu
werden, da sie zum selben Namensbereich (name2) gehört wie
die Funktion h selbst.
Die Funktionen f und g gehören zum
Namensbereich name1 und müssen somit qualifiziert
werden.
string und cout gehören zur
Standardbibliothek und somit zum Namensbereich
std.
Der Sinn von Namensbereichen ist an dieser Stelle vielleicht nicht ersichtlich, aber, wenn man sich ein großes Projekt mit vielen Hunderten von Klassen und Funktionen vorstellt, wird einem schnell klar, dass durch Namensbereiche Namenskollisionen vermieden werden, die gerade bei großen Projekten nur schwer zu finden sind.
Wird ein Name häufig außerhalb seines Namensbereichs benutzt, wird es
schnell lästig und auch unübersichtlich, ihn immer wieder zu
qualifizieren. Dies kann mit Hilfe der using-Deklaration
vermieden werden, die ein lokales Synonym erzeugt. Es können auch alle
Namen eines Namensbereichs mit der using-Direktive
verfügbar gemacht werden. Man betrachte für die beiden Varianten von
using folgendes Beispiel:
#include <iostream>
#include <string>
using namespace std; // using Direktive
namespace name1
{
double f();
int g(int i);
}
namespace name2
{
void h(string s);
int number;
using name1::f; // using Deklaration
}
double name1::f() { /*...*/ }
int name1::g(int i) { /*...*/ }
void name2::h(string s)
{
using name1::g; // using Deklaration
cout << s << f() << " " << g(number) << endl;
}Anmerkungen:
Aufgrund der using-Direktive können alle Namen der
C++ Standardbibliothek in diesem Beispiel ohne Qualifizierer benutzt
werden. Da diese Form der Veröffentlichung von Namen den Mechanismus der
Namensbereiche zunichte macht, sollte eine globale
using-Direktive eher sparsam eingesetzt werden. Vor allem
sollte sie, wenn möglich, in Headerdateien vermieden werden, weil
automatisch alle Dateien, die diese Datei einbinden, sie auch
beinhalten.
Es ist meistens eine gute Idee, eine
using-Deklaration so lokal wie möglich zu halten. Speziell
sollte man sich bei using-Deklarationen innerhalb einer
Namensbereichsdefinition überlegen, ob alle Funktionen einen Bezug zu
dem Synonym haben.
Da im Praktikum nur mit dem Namensraum std der
Standardbibliothek gearbeitet wird, kann dort zur Vereinfachung von
dieser Regel abgewichen werden und die Anweisung
cpp using namespace std; in allen .cpp- und .h-Dateien
nach den Includes der Standardbibliothek eingesetzt werden.