Namensbereiche (namespace)

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