namespace

Namespace - zu deutsch Namensraum kennzeichnet Einheiten die zusammengehören. zB ist die gesamt C++ Standard Library im namespace std zu finden. Namespace verhindern Namenskonflikte und teilen den Code in logische Einheiten auf. Kaum einer kennt die Standard Library wirklich auswendig. Es kann also passieren, dass man für eine Klasse einen Namen verwendet, den es bereits gibt -> das führt zu Problmen. Es muss ja auch kein Namenskonflikt mit der Standard Bibliothek sein, man kann ja auch mit anderen Bibliotheken solche Probleme bekommen.

In C verwendete man Prefixe, also statt class Integer, schrieb man class myInteger. Sowas ist aber auf dauer unbefriedigend.

Wir haben bereits Namensräume kennengelernt: using namespace std;. Dies ist eine using-Direktive, sie importiert alle Namen des Namensraumes std in den aktuellen (in unserem Fall den globalen) Namensraum. Mittels der using-Deklaration using std::cout; könnten wir nur cout importieren und alle anderen Namen unangetastet lassen.

Wie wir bereits gesehen haben kann man mittels :: in einen Namensraum eindringen. So sind folgende beide Programme äquivalent:

    #include <iostream>
    using namespace std;

    int main()
    {
      int i;
      cout<<"Bitte eine Zahl eingeben: ";
      cin>>i;
      cout<<"Sie haben "<<i<<" eingegeben.\n";
    }

    ////////////////////////////////////////////

    #include <iostream>

    int main()
    {
      int i;
      std::cout<<"Bitte eine Zahl eingeben: ";
      std::cin>>i;
      std::cout<<"Sie haben "<<i<<" eingegeben.\n";
    }
    

Obwohl der Code mit std::cout schwerer zu lesen ist als mit using namespace std; sollte man trotzdem using Direktiven und Deklarationen überlegt einsetzen. Denn gerade eine using-Direktive bricht das Konzept von Namensräumen gewaltig.

Einen eigenen Namensraum zu erstellen ist ganz simpel:

    #include <iostream>
    using namespace std;

    int var;

    namespace myNS
    {
      int var;
      class Test
      {
      public:
        void foo()
        {
          std::cout << ::var << " == globales var in myNS::Test::foo\n";
          std::cout << var <<" == myNS::var in myNS::Test::foo\n";
        }
      };
    }

    class Test
    {
    };

    int main()
    {
      var = 3;
      myNS::var=7;
      myNS::Test t;
      t.foo();
    }
    

Mittels ::var greifen wir auf das globale var zu. Wenn wir auf einen anderen Namespace zugreifen wollen verwenden wir std::cout. Sollte myNS einen Namensraum std beinhalten, würden wir damit aber auch myNS::std anstatt auf std zugreifen. In diesem Fall schreiben wir ::std::cout. Mit ::std springen wir wieder in den globalen Namensraum und suchen dort nach std.

Es gibt eine besondere Art von Namensräumen: unnamed namespaces - Namenlose Namensräume.

    #include <iostream>
    using namespace std;

    namespace myNS
    {
      namespace
      {
        int var;
      }
      void setVar(int i) { var=i; }

      class Test
      {
      public:
        void foo()
        {
          std::cout << var <<" == myNS::var in myNS::Test::foo\n";
        }
      };
    }

    int main()
    {
      using myNS::Test;
      myNS::var=3;
      myNS::setVar(4);
      Test t;
      t.foo();
    }
    

var ist nur innerhalb dieser Übersetzungseinheit sichtbar. Andere Übersetzungseinheiten könnten nicht myNS::var=3; schreiben, sondern müssten myNS::setVar() verwenden. Da main() in der gleichen Übersetzungseinheit wie myNS::var liegt, kann main aber trotzdem auf var zugreifen. Was Übersetzungseinheiten sind lernen wir aber erst später.

top