Wann Namespace, und wie?



  • Wann sollte man einen eigenen namensraum verwenden?
    Und wie kann ich funktionen und klassen, die über mehrere Quelldateien gehen (klassen in class.cpp,class.h und funktionen in func.cpp,func.h) in einen namensraum packen?



  • Du kannst z.B. in den Headern folgendes Schreiben:

    // class.h
    namespace myns {
      class A {
        ...
      };
      class B {
        ...
      }
    }
    
    // class.cpp
    #include "class.h"
    using namespace myns;
    
    A::A() {
    }
    ...
    B::B() {
    }
    ...
    

    Leider kann ich nicht viel aus meiner Erfahrung sagen, da diese noch ziemlich gering ist, wann es sinnvoll ist, aber ich denke, wenn man z.B. Funktionen und Klassen für mathematische Berechnungen hat, dann sollte man diese in einen namespace mathe oder so packen, usw. Einfach nur zu sauberen Strukturierung. Aber das ist wohl auch ein wenig Geschmackssache.



  • und wie sieht es mit verschiedenen headern aus?

    Wie kann ich da mehrere in einen namensraum nehmen??



  • Ganz einfach wieder in den Namespace schreiben, also:

    // class1.h
    namespace myns {
      class A {
      };
    }
    
    // class2.h
    namespace myns {
      class B {
      };
    }
    

    Der Namespace wird dann einfach erweitert, nicht überschrieben, wie Du evtl. vermuten könntest.



  • ja das habe ich vermutet =)!
    und ist die obige lösung, mit den .cpp dateien zu den .h dateien auch richtig?



  • Ja, Du kannst es so machen. Ich mache es z.B. eigentlich immer so:

    2 Klassen, also 4 Dateien (class1.h, class2.cpp, class2.h, class2.cpp)

    // class1.h
    #ifndef __CLASS1_H
    #define __CLASS1_H
    namespace myns {
      class class1 {
        ...
      };
    }
    #endif
    
    // class1.cpp
    #include "class1.h"
    using namespace myns;
    class1::class1() {
    }
    ...
    
    // class2.h
    #ifndef __CLASS2_H
    #define __CLASS2_H
    namespace myns {
      class2 {
        ...
      };
    }
    #endif
    
    // class2.cpp
    #include "class2.h"
    using namespace myns;
    class2::class2() {
    }
    ...
    

    So hast Du für jede Klasse eine eigene Datei und die Struktur findest Du im Dateisystem wieder. Für den Namespace könntest Du ein Unterverzeichnis erstellen, wo Du dann die anderen Dateien reinpackst. Außerdem kannst Du noch eine alltemeine Headerdatei erstellen, wo dann alle Klassen und Funktionsdateien inkludiert werden.

    // myns.h
    #ifndef __MYNS_H
    #define __MYNS_H
    
    #include "class1.h"
    #include "class2.h"
    ...
    #endif
    

    Dann hast Du z.B. folgende Sturktur:

    myns (verzeichnis)
    +- class1.cpp
    +- class1.h
    +- class2.cpp
    +- class2.h
    +- myns.h
    

    Für ne Lib oder so finde ich das z.B. sehr übersichtlich und geordnet. Und wenn Du alles inkludieren möchtest, dann schreibst Du einfach

    #include "myns\\myns.h"
    

    und fertig.
    Die Präprozessor-Anweisungen würde ich mit reinnehmen, da es ja schonmal sein kann, dass eine Headerdatei mehrmals inkludiert wird, z.B. bei Vererbung, so sicherst Du das mit ab. Ist so, denke ich, ziemlich strukturiert und sauber.
    Wenn jmd. anderer Meinung ist, dann nur zu, wie gesagt, ich lerne auch noch. 😃



  • so habb jetzt mal was probiert...geht nicht:
    Da ich grad an einem seriennummernprogramm schreibe, habe ich die klassen mal so genannt!

    Fehler hab ich im Code benannt, unten steht Meldung dazu!

    //serial_exception.h
    //---------------------------------------------------------------------------
    
    #ifndef serial_exceptionH
    #define serial_exceptionH
    
    namespace serial
    {
     class MyException:public std::runtime_error
     {
      public:
      MyException(const std::string& msg):std::runtime_error(msg){}
     };
     class MyException2:public std::runtime_error
     {
      public:
      MyException2(const std::string& msg):std::runtime_error(msg){}
     };
    
    }
    //---------------------------------------------------------------------------
    #endif
    

    in der cpp steht nix drin, brauch ich ja nix!

    //serial_func.h
    //---------------------------------------------------------------------------
    
    #ifndef serial_funcH
    #define serial_funcH
    namespace serial
    {
    void Tester();
    void ClassTester(Tserial &t);   //Fehler 1
    void ExceptionT(int z);
    }
    //---------------------------------------------------------------------------
    #endif
    
    //serial_func.cpp
    //---------------------------------------------------------------------------
    
    #pragma hdrstop
    
    #include <iostream>
    #include <conio>
    #include "serial_func.h"
    #include "serial_class.h"
    #include "serial_exception.h"
    using namespace std;
    using namespace serial;
    
    //---------------------------------------------------------------------------
    void Tester()
    {
     cout<<"serial_func tester()"<<endl;
    }
    void ClassTester(Tserial& t)
    {
     t.TestIt();
    }
    
    void ExceptionT(int z)
    {
     if(z==0)
      throw MyException("Fehler, Zahl ist 0");
     else
      throw MyException2("Fehler: Exc2, Zahl groesser null");
    } 
    
    #pragma package(smart_init)
    
    //serial_class.h
    //---------------------------------------------------------------------------
    
    #ifndef serial_classH
    #define serial_classH
    namespace serial
    {
     class Tserial
     {
     public:
      void TestIt()const;
     };
    
    }
    //---------------------------------------------------------------------------
    #endif
    
    //serial_class.cpp
    //---------------------------------------------------------------------------
    
    #pragma hdrstop
    
    #include "serial_class.h"
    #include <iostream>
    #include <conio>
    
    using namespace std;
    using namespace serial;
    
    //---------------------------------------------------------------------------
    
    void Tserial::TestIt()const
    {
     cout<<"Namespace serial, klasse serial"<<endl;
    }
    
    #pragma package(smart_init)
    
    //Hauptprogramm
    //---------------------------------------------------------------------------
    
    #include <vcl.h>
    #pragma hdrstop
    #include <iostream>
    #include <conio>
    #include "serial_exception.h"
    #include "serial_func.h"
    #include "serial_class.h"
    using namespace std;
    using namespace serial;
    
    //---------------------------------------------------------------------------
    
    #pragma argsused
    int main(int argc, char* argv[])
    {
     ExceptionT(0);  //wahrscheinlich Fehler2 hier
     getch();       return 0;
    }
    //---------------------------------------------------------------------------
    

    So nun zu den Fehlermeldungen:

    Fehler 1: "Parameterdeklaration darf nicht mit Tserial beginnen"
    Fehler 2: (linker Fehler)
              "Unresolved external 'serial::ExceptionT(int)' referenced from (Pfad---SERIAL.OBJ)
    

    hoffe mir kann hier jemand helfen



  • du mußt in serial_func.h den header serial_class.h includen, weil du in serial_func.h die klasse Tserial verwendest. am besten du includest sie auch noch in serial_func.cpp. auf indirekte includes ("serial_class.h brauch ich ja in serial_func.cpp nicht zu includen, die ist ja schon in serial_func.h drin") solltest du dich nicht verlassen. es könnte ja sein, daß du serial_func.h mal änderst und dann ist serial_class.h vielleicht nicht mehr drin.

    da du sie dort nicht includest, ist Tserial dort nicht deklariert und du bekommst die fehlermeldung, daß Tserial in der deklaration der funktionsparameter von ClassTester() nicht verwendet werden darf.

    die zweite fehlermeldung rührt daher, daß aufgrund des ersten fehlers die datei serial_func.cpp nicht kompiliert wurde. und deswegen kann der linker die dort vorhandene funktion ExceptionT() auch nicht finden.



  • also ich hab das jetzt geändert, aber der 2te fehler ist immernoch da!



  • Du solltest auch die Definition von ExceptionT im Namensraum serial machen.

    namespace serial
    {
      void ExceptionT(int z)
      {
       if(z==0)
        throw MyException("Fehler, Zahl ist 0");
       else
        throw MyException2("Fehler: Exc2, Zahl groesser null");
      }
    }
    


  • also geht es doch nicht wie mantiz geschrieben hat?
    also ein using namespace reicht doch nicht?
    Weil das habe ich ja in der cpp wo die definition der funktion ist gemacht!



  • Mit using namespace serial öffnest du den Namensraum serial in deiner cpp. Deswegen weiß der arme Compiler aber immer noch nicht wozu ExceptionT gehört. Das mußt du ihm schon sagen.



  • Ach, so meintest Du das. Sorry, dann hatte ich das falsch verstanden. 😞
    Mit "using namespace" kannst Du nur direkt auf die Elemente davon zugreifen, definiert werden müssen die aber dann schon vorher. Ich dachte Du meintest in der cpp-Datei sowas:

    using namespace myns {
    
      int test() {
        return 10;
      }
      ...
    
    }
    

    das könntest Du dann so aufteilen:

    // .h-File
    namespace myns {
      int test();
    }
    
    // .cpp-File
    using namespace myns;
    int test() {
      return 10;
    }
    

    Oder halt mit Klassen.



  • lol mantiz, irgendwie erklärst schonwieder das gleiche!



  • Ja eigentlich schon, aber ist das falsch? 😕

    ich dachte erst wellness meinte mit der Frage, ob man das auf cpp-Dateien übertragen könnte, dass man innerhalb der cpp-Datei sowas machen könnte:

    namespace myns {
      ...
    }
    

    aber er hatte es wohl so verstanden, dass man sich mit "using namespace ..." innerhalb der cpp-Datei in dem Namespace befindet, aber das ist ja nicht so, man kann dann nur direkt, also ohne den Namespace noch angeben zu müssen auf die Elemente davon zugreifen, die aber bereits existieren müssen. Erweitern kann man den Namespace so nicht.

    Oder sehe ich da jetzt was falsch? Wie gesagt, so gross ist meine Erfahrung da jetzt auch noch nicht. 🙂



  • nee das siehst schon richtig...nur er meinte wohl was andres, und zwar, wie man die klassen methoden etc definiert!

    Er wollte nicht nur auf den namespace zugreifen, sondern seine klassenmethoden implementieren!


Log in to reply