Je größer ein Projekt wird, und je mehr Teile dazu aus unterschiedlichen Quellen dafür zusammengeschraubt werden, desto größer wird die Wahrscheinlichkeit von Namenskollisionen, insbesondere bei global gültigen Namen (globale Variablen, Typen, Funktionen).
Dies ist leider nicht immer zu vermeiden.
Um das Problem in den Griff zu bekommen, gibt es in C++ Namensbereiche (name spaces).
Sinnigerweise heißt das zugehörige Schlüsselwort namespace.
Dahinter steckt die Idee, jeden verwendeten Namen einem Namensbereich zuzuordnen, in dem der Name eindeutig sein muß. Damit werden Kollisionen zwischen Namen nur noch innerhalb des Namensbereichs möglich, anstatt innerhalb des ganzen Programms.
Beispielsweise sind alle Namen der Standardbibliothek (auch die Namen der alten ANSI-C-Funktionen und -Typen) im Namensbereich std deklariert.
In einem anderen Namensbereich können die selben Namen nochmals vergeben werden.
Zu jedem Zeitpunkt kann es einen oder mehrere voreingestellte Namensbereiche geben; die darin deklarierten Namen können direkt verwendet werden solange sie nicht kollidieren. Allen anderen Namen wird ihr jeweiliger Namensbereich vorangestellt (getrennt mit einem scope operator ::; siehe scope resolution operator ::).
Einen voreingestellten Namensbereich kann man
mit
using namespace Name des Namensbereichs;
einführen.
Weiterhin kann man gezielt einzelne Namen einem Namensbereich zuordnen
mit:
using Name des Namensbereichs::Name;
Eine using-Anweisung gilt bis zum Ende des umgebenden Blocks; beziehungsweise bis zum Ende des Quelltextes, wenn sie außerhalb einer Funktion steht.
Dies wird alles in dem folgenden kleinen Programm gezeigt:
// Time-stamp: "10.01.04 13:18 namespacedemo.cpp klaus@wachtler.de" namespace Microsoft { enum charakter_t { ganz_mies, mies }; // Datentyp charakter_t chef; // globale Variable Microsoft::chef charakter_t knecht[10000]; // globales Feld Microsoft::knecht } namespace Oracle { enum charakter_t { ganz_mies, mies, geht_so }; // Datentyp charakter_t chef; // globale Variable Oracle::chef charakter_t knecht[2000]; // globales Feld Oracle::knecht charakter_t pfoertner; // globale Variable Oracle::pfoertner } int main( int nargs, char **args ) { Microsoft::chef = Microsoft::ganz_mies; // voll qualifiziert Oracle::chef = Oracle::mies; // ebenfalls using namespace Microsoft; chef = ganz_mies; // entspricht Microsoft::chef = Microsoft::ganz_mies knecht[0] = mies; // entspricht Microsoft::knecht[0] = Microsoft::mies // falsch, weil Oracle nicht mit using namespace geöffnet wurde: // pfoertner = geht_so; // Aber nach einem using namespace geht es: using namespace Oracle; // jetzt sind sowohl Microsoft als auch Oracle offen pfoertner = geht_so; // sowohl pfoertner als auch geht_so sind eindeutig // falsch, da nicht eindeutig: // Microsoft::chef oder Oracle::chef? // Ebenso Microsoft::ganz_mies oder Oracle::ganz_mies? // chef = ganz_mies; { // Man kann aber für einzelne Namen eine Voreinstellung wählen: using Microsoft::chef; using Microsoft::ganz_mies; // jetzt klappt es: chef = ganz_mies; } // jetzt wieder falsch, da die beiden using Microsoft::chef // und using Microsoft::ganz_mies nur im Block stehen, der // bereits verlassen wurde: // chef = ganz_mies; } // main( int nargs, char **args )
Durch wiederholte namespace
Name d. Namesp.{
...}
-Blöcke
kann man zu einem bereits existierenden Namensbereich weitere Namen
hinzufügen. Ein Entfernen bereits enthaltener Namen ist nicht
möglich:
namespace EinNamespace { int i; } // ... namespace EinNamespace { int j; } // ... EinNamespace::i = 25; EinNamespace::j = 13;
Hat man einen Namensbereich bereits definiert, dann kann man mit einer Art Zuweisung dafür noch einen anderen Namen vergeben:
namespace EinFurchtbarLangerName { int i; } namespace EFLN = EinFurchtbarLangerName; // ... EinFurchtbarLangerName::i = 25; EFLN::i = 25; // identisch!
AnyWare@Wachtler.de