namespace VS abstrakte Klasse



  • Hi, ich hab mit C++ bisher noch nicht so viel am Hut gehabt. Da ich mich allerdings zZ etwas mehr damit beschäftigen möchte, wollte ich mir mal ein paar eigene nützliche Funktionen als Bibliothek anlegen.

    Dabei ist mir allerdings eine Frage aufgefallen:
    Wo liegt der unterschied für mich als Programmierer, zwischen einem namespace und einer abstrakten klasse mit statischen Methoden? Welche vor und Nachteile existieren jeweils, und was ist wann/immer zu empfehlen?

    also zb:

    class myMath
     {
     private:
    	 virtual bool ab() = 0;
    public:
    	int static square(int, int);
    };
    

    oder

    namespace myMath{
    	int square(int, int);
    }
    

    Auf beide dürfte ich ja mit

    int tmp = myMath::square(5,6);
    

    zugreifen können oder?

    Schonmal danke im vor raus.



  • Eine Klasse als reine Sammlung von statischen Methoden zu verwenden halte ich für Unsinn. Wenn du sowas benötigst, ist ein Namensraum genau das richtige.



  • Da stimme ich CStoll vollkommen zu, dafür eine Klasse zuverwenden finde ich absolut sinnlos, vor allem da du sie ja extra noch abstrakt machst, sie also sonst gar nicht nutzen willst.

    Lg freeG



  • Statt dem abstrakt machen hätte es auch ein privater Konstruktor getan.
    Ein klarer Vorteil des Namespace ist, dass er komplett oder in Teilen mit using importiert werden kann. Außerdem kann man ein Namensspacealias erstellen. Beides geht mit Klassen nicht.



  • Für wichtiger halte ich es eigentlich, dass ein Namensraum erweiterbar ist - du musst nicht alle Bestandteile eines Namensraumes im selben Header deklarieren. Gerade, wenn es um potentiell sehr große Funktionssammlungen geht, wie es bei mathematischen Funktionen ja durchaus der Fall sein kann, ist das ein großer organisatorischer Vorteil.

    Ansonsten gibt es im Zusammenhang mit benutzerdefinierten Typen noch den Unterschied, dass ggf. ADNL greift. Beispiel:

    namespace foo {
      struct bar { };
      void baz(bar const &) { }
    };
    
    int main() {
      foo::bar qux;
      baz(qux); // keine Qualifizierung notwendig, qux stammt aus namespace foo
    }
    


  • seldon schrieb:

    Für wichtiger halte ich es eigentlich, dass ein Namensraum erweiterbar ist

    Ja. Ein Bug von C++, daß man Klassen nicht nachträglich verfummeln kann. Richtig wäre es, daß man alles kann, aber wie gewohnt sehr wenig sollte.



  • Es gibt hier einen großen, qualitativen Unterschied zwischen Klassen und Namensräumen: Eine Klasse ist eine Einheit, ein Namensraum ist eine Sammlung. Es ist für einen Namensraum wenig problematisch, wenn weitere Funktionen in ihn hineingepackt werden, bei einer Klasse dagegen sieht das ganz anders aus. Es wäre ein Wartungsalbtraum, wenn benutzender Code die Kapselung einer Klasse völlig umgehen und in ihren Interna herumfuhrwerken könnte. Die Implementation der Kernklasse könnte sich auf keine Invariante mehr verlassen, und wenn eine Klasse von verschiedenen Leuten Erweiterungen bekäme, die sich auf verschiedene Dinge verlassen, von denen die anderen jeweils nichts wissen, wünschte man sich schnell, man müsse sich nur mit Spaghetticode herumschlagen. Noch schlimmer ist die Vorstellung, dass Erweiterungen die Schnittstelle der Klasse verändern - Methoden überladen oder neue Member einführen, die besondere Behandlung erforden. Nachher sitze ich da und stopfe in einer anderen Klasse Zeiger in shared_ptrs, ohne eine Ahnung zu haben, dass ich vor der Zerstörung noch eine mir unbekannte Methode aufrufen müsste, die jemand rangepatcht hat.

    Ich habe prinzipiell etwas übrig für die Ansicht, dass der Programmierer schon selbst aufpassen muss, dass er sich nicht das Bein abhackt, aber, um bei der Metapher zu bleiben, er sollte sich schon darauf verlassen können, dass der Axtkopf nicht auf einmal einen Meter länger wird. Schnittstellen müssen feststehen. Sie sind das, auf das ich mich verlassen können muss, damit ich mein Bein behalte. Wenn ich damit rechnen muss, dass die Klasse, die ein zweiter geschrieben hat, bevor sie bei mir ankommt von einem dritten verändert wurde, von dem ich womöglich noch nicht mal etwas weiß, kann ich damit überhaupt nicht vernünftig umgehen. Und wenn so etwas mal hochgeht, sucht man tagelang an völlig falschen Stellen nach dem Fehler.

    Davon ganz abgesehen wäre die technische Umsetzung eines solchen Vorhabens im C++-Speichermodell ausgesprochen schwierig.



  • volkard schrieb:

    seldon schrieb:

    Für wichtiger halte ich es eigentlich, dass ein Namensraum erweiterbar ist

    Ja. Ein Bug von C++, daß man Klassen nicht nachträglich verfummeln kann. Richtig wäre es, daß man alles kann, aber wie gewohnt sehr wenig sollte.

    Also ich bin froh dass es nicht geht.



  • Ok, also wenn ich das richtig verstehe kann man zusammenfassen, dass ein Namensraum immer einer klasse mit statischen Methoden vorzuziehen ist.

    Mir kam die frage auf, da ich mich, aufgrund des Infounterrichts, mit Java befassen musste, und da ist ja mehr die Version mit den Klassen verbreitet.

    Und damit kann man ja auch unter c++ Vererbungsketten aufbauen, das man also Funktionen für Algebra und Analysis auf 2 Klassen aufteilt und MyMath dann von beiden erbt.



  • Bloß: Vererbung ist nicht die richtige Beziehung.

    Mit einer using-Direktive geht das aber auch mit Namespaces:

    namespace foo { void foo(); }
    namespace bar { void bar(); }
    
    namespace qux {
      using namespace foo;
      using namespace bar;
    }
    
    //...
    qux::foo();
    


  • Ah, jetzt kam ich ein bisschen zu spät. Man kann es so machen, wie davie beschreibt, allerdings ist das Vorgehen in C++ eher unüblich. Man würde sich im Zweifel die zwei Teilnamensräume sparen und die Funktionen einfach im selben Namensraum aber verschiedenen Headern deklarieren.


Log in to reply