Wann und Warum static?



  • Tag zusammen,

    mir geistert seit eingier Zeit die Frage durch den Kopf, wofür ist static (in Klassen) da?

    Was es macht ist mir klar, aber wann benutzt man es, bzw. warum wird überall davon abgeraten es zu nutzen?

    Das kam mir mal wieder siedend-heiss, als hustbaer in einem anderen Thread das hier aussprach:

    hustbaer schrieb:

    "inline" vor die Funktions-Definitionen schreiben wirkt auch Wunder.
    Natürlich nicht bei statischen Membern, aber davon sollte man sowieso keine haben.

    (Ich wollte dort nur nicht offtopic reinplatzen, daher dieser neue Thread.)

    Per google hab ich nichts gefunden, was mich befriedigt...



  • Statische Membervariablen teilen im Prinzip die gleichen Probleme wie globale Variablen.



  • Statische Membervariablen teilen im Prinzip die gleichen Probleme wie globale Variablen.

    Statische Memberfunktionen dementsprechend die der globalen funktionen.

    Aber:
    Es gibt Anwendungsfälle da braucht man sie ....
    Es gibt nun mal ressourcen die haben einen Globalen Charackter, trotz das sie zu einem Klassenkontext gehoeren
    Genau so gibt es funktionen, die sollen/muessen ohne Instanzen laufen, und gehoeren aber logisch zu einer Klasse zu (Erzeuger Methoden z.b.), bzw man baut logisch eine Klasse (namespace) drumherum (Math::Pi oder solche Konstrukte).

    Durch die Zuordnung zu einer Klasse macht man diese Globalen Dinger aber strukturierter und damit wartbarer, und eliminiert damit zumindest einen der Nachteile purer Globaler Dinger ...

    Ciao ....



  • RHBaum schrieb:

    Statische Memberfunktionen dementsprechend die der globalen funktionen.

    Was ist das Problem von globalen Funktionen?



  • Nexus schrieb:

    RHBaum schrieb:

    Statische Memberfunktionen dementsprechend die der globalen funktionen.

    Was ist das Problem von globalen Funktionen?

    Das wäre auch meine nächste Frage gewesen. Meyers sagt dazu, dass man freie Funktionen vor Memberfunktionen bevorzugen soll...



  • Meyers sagt dazu, dass man freie Funktionen vor Memberfunktionen bevorzugen soll...

    Glaub ich nicht,das er das so generell sagt ... Wo ?

    Es macht keinen Sinn, eine "lose" funktion auf teufel komm raus an eine klasse zu hängen.
    Es macht aber auch keinen Sinn, eine Statische klassenfunktion, wenn sie zu der klasse gehört, von ihrem Klassenkontext zu befreien.

    Was ist das Problem von globalen Funktionen?

    1. Name-kollisionen, ok nicht wirklich unter c++, durch mehrfachüberladungen isses abgemildert. Aber uebersichtlichkeit kann nen Problem werden.
    2. fehlender Zugriffsschutz. Ist eine globale funktion sichtbar, kann ich nicht mehr sagen, das wer sie nicht wervenden soll, ausser ich schreib ellenlange Doku.

    Ciao ...



  • RHBaum schrieb:

    Meyers sagt dazu, dass man freie Funktionen vor Memberfunktionen bevorzugen soll...

    Glaub ich nicht,das er das so generell sagt ... Wo ?

    In der Auflage von 2005 (müsste die 3. sein) in Item 23:

    Scott Meyers schrieb:

    Item 23: Prefer non-member non-friend functions to member functions

    Scott Meyers schrieb:

    Things to Remember

    Prefer non-member non-friend functions to member functions. Doing so increases encapsulation, packaging flexibility, and functional extensibility.

    Nachschauen darfst du selbst nochmal, er geht da natürlich auch drauf ein, wie, warum, wann un wieso und was und welche Farbe und wohin...
    Wie gewohnt halt bei ihm.

    Meine Aussage soll auch nicht bedeuten, dass ich erstens dasselbe denke und zweitens dass ich fordere, dass Methoden böse sind und alles global sein soll.



  • RHBaum schrieb:

    1. Name-kollisionen, ok nicht wirklich unter c++, durch mehrfachüberladungen isses abgemildert.

    Ja, und vor allem durch Namensräume. Davon abgesehen kann ADL gerade ein Feature sein.

    RHBaum schrieb:

    2. fehlender Zugriffsschutz. Ist eine globale funktion sichtbar, kann ich nicht mehr sagen, das wer sie nicht wervenden soll, ausser ich schreib ellenlange Doku.

    Gleiches gilt für public -Funktionen. Oder für Klassen. Oder so ziemlich alles. Wenn man sie nicht verwenden soll, macht man sie eben nicht im öffentlichen API sichtbar. Eine Dokumentation ist sowieso notwendig, um den Verwendungszweck zu erfahren -- das ist kein spezifisches Problem globaler Funktionen.

    Ich würde globale Funktionen nicht mit globalen Variablen vergleichen. Die Problematik ist komplett eine andere, genauer gesagt gibt es für globale Funktionen gar keine.

    Skym0sh0 schrieb:

    Meyers sagt dazu, dass man freie Funktionen vor Memberfunktionen bevorzugen soll...

    Grundsätzlich stimmt das, aber zu strikt genommen ist das impraktikabel. Es ist oft auch sinnvoll, Methoden in die Klasse zu nehmen, die keinen direkten Zugriff auf Interna benötigen. Alleine schon aus Konsistenzgründen.

    class Shape
    {
        float getLeft() const;
        float getWidth() const;
    };
    
    // implementierbar über Public API
    float getRight(const Shape& g);
    
    // toll, jetzt hat man g.getLeft(), aber getRight(g);
    


  • Die Aussage von Meyers bezieht sich auf nicht-statische Methoden. Seine Begründung dafür ist dass die Kapselung davon profitiert, wenn weniger Code zugriff auf die Interna einer Klasse hat. Mit statischen Methoden hat das aber eher weniger zu tun.

    @RHBaum wtf sind "mehrfachüberladungen"? 😃

    @Skym0sh0 Anfangsfrage:
    Wenn etwas zur Klasse gehört aber nicht zu einem bestimmten Objekt, dann macht man es statisch. Eigentlich relativ offensichtlich. Oft braucht man das natürlich nicht, und wenn das so ist ist das eher ein gutes als ein schlechtes Zeichen. Ich habe allerdings z.B. öfter mal private statische Hilfsmethoden, weil man sowas bei Templates nicht in der Implementierungsdatei in einem anonymen namespace verstecken kann. Ein weiteres Beispiel für statische Methoden sind Singletons. (Welche übrigens generell als Antipattern gesehen werden, was ich auch verstehen kann, aber für Startup-Kram sind sie dennoch nützlich. z.B. für WSAStartup() bei Sockets.)



  • Ich denke auch nicht so ...

    zum beispiel hab ich oft den fall, das ich Objekte unterschiedlichen types mergen, oder convertieren muss ...

    ALso brauch ich sowas ca.

    int convert(const A * pFrom,B * pTo);

    da ich soweiso meist in nem Namspace bin, waers auch ok ....
    wenn die Funktion einfach zu implementieren waer.
    Isses aber meist nicht. DIe wuerde dann vielleicht mehrere tausend codezeilen gross, was doof und unleserlich ist. Oft brauch ich auch rekursion drinn.

    Also muss ich sie unterteilen.

    Ohne Klassencontext wuerd ich meinen Namespace zumüllen mit tonnen an funktionen ala convert_xyz ....

    nur lokal definieren in der cpp für die convert funktion ... brauchst aber richtige Reihenfolge, bzw forward deklarationen in der cpp.
    Waer machbar.

    Die funktionen alle in nen eigenen namespace packen ?
    find ich auch weniger schön ...

    Ich nutzt aber dann meist klassen ...

    sowas wie

    class XYZConverter
    {
    public:
        static int convert(const A * pFrom,B * pTo); 
    private:
        static int convert_xyz(....)
        ..... 
    };
    

    und nutzen tu ich dann

    iResult =XYZConverter::convert(a,b);

    Ich konnt mit nem globalen

    inline int convert(const A * pFrom,B * pTo){ return XYZConverter::convert(a,b);}
    

    die sache natuerlich global machen, aber warum ?
    So sehr stört mich die klassenkontext dann doch nicht.

    Der Vorteil der Klassenversion gegenueber lokalen funktionen ist, wenn man mit Visual Studio arbeitet, es lässt sich besser navigieren, da tut sich der VS leichter ^^

    "Probleme" haben beide Lösungen nicht, es ist reine Formsache, der compiler compiliert den Klassencontext eh weg ...
    Das Erstellen der standard Konstruktoren könnt ich auch noch verhindern wenns mich stören würde.
    Nen normaler compiler generiert die auch nicht, wenn man keine instanz erzeugt ...

    Ciao ...



  • D.h. statt eigene Namespaces oder als freie Funktionen baust du dir für naja größere Probleme eine Klasse mit nur statischen Methoden?! (Letztlich ja nur wegen der Namensgebung...)

    Mh, hör sich in meinen Ohren so etwas komisch an, weil dann hätteste direkt ne richtige Klasse bauen können, die genau für sowas zuständig ist.



  • @RHBaum wtf sind "mehrfachüberladungen"?

    Na wenn man die Überladung überlad .... 😃
    Sorry, Überladung hätte ausgereicht ^^

    weil dann hätteste direkt ne richtige Klasse bauen können

    Was verstehst du unter richtige Klasse ?
    Eine die man instanzieren muss ?

    Wenn A nach B konvertiert werden soll.
    Gehört das zu A oder zu B ? Schwer zu sagen oder ? Abhängig isses von beiden ...
    es an A oder B zu hängen macht oft keinen Sinn ...
    Aber dafuer noch ne Klasse C zu instanzieren, macht auch kein sinn ...

    Also iss ne globale oder pseudo globale Funktion dafuer schon eher sinnvoll.

    Ciao ...



  • Also Klassen als Namespace zu misbrauchen halte ich doch für eine etwas fragwürdige Praxis. 😉



  • Wenn das so weitergeht, muss der Thread bald ins Java-Forum.

    Pack die Implementationsroutinen in der ÜE in den namenslosen Namensraum, wo sie keiner sieht und sie keinen stören; dann kann der Compiler auch besser optimieren (weil er weiß, dass die anderswo nicht gebraucht werden). Forward-Deklarationen braucht das womöglich, aber die hast du im Moment auch (nur halt in der "Klasse").



  • RHBaum schrieb:

    weil dann hätteste direkt ne richtige Klasse bauen können

    Was verstehst du unter richtige Klasse ?
    Eine die man instanzieren muss ?

    Ja

    RHBaum schrieb:

    Wenn A nach B konvertiert werden soll.
    Gehört das zu A oder zu B ? Schwer zu sagen oder ? Abhängig isses von beiden ...
    es an A oder B zu hängen macht oft keinen Sinn ...
    Aber dafuer noch ne Klasse C zu instanzieren, macht auch kein sinn ...

    Naja, wenn du möchtest, dass eine Klasse A aus einer Klasse B erstellt werden kann (was anderes ist eine Konvertierung ja nicht), dann biete einen ensprechenden Konstruktor an. Und zack, da hast du deine Konvertierungsfunktion.



  • Was ist genau der Nachteil?

    Die Technik ist an sich nicht ungewöhnlich ...
    Templateprogrammierung, Wenn man mehrere Funktionen gleichzeitig mit nur einem Typ Switchen will / muss , Policy-Klassen ...

    Weil ich es hier ohne templates mache, ist es böse ?

    Ciao ...



  • Der Nachteil ist dass diese Funktionen nach außen sichtbar sind und den Header zu müllen. Und bei Templates hat man keine Wahl, deshalb ist das da akzeptiert.



  • Mir ist nicht ganz klar, was du mit "mehrere Funktionen gleichzeitig mit nur einem Typ Switchen will / muss" meinst. Was den anderen Kram angeht, so ist Templatemetafoo ein ganz anderer Hund; wenn du das Typsystem programmieren willst, kommst du um Typen nicht wirklich herum (und Namespace-Templates gibt's halt nicht, obwohl das vielleicht mal ne Idee wäre).

    Aber es geht auch gar nicht um böse oder nicht, sondern darum, ohne Not die Beschränkungen einer Klasse in Kauf zu nehmen. Du musst den gesamten Inhalt der Klasse samt privater Funktionen (also Implementationsdetails) im Header bekannt machen, was konzeptionell unschön ist und bei jeder Änderung der Interna dazu führt, dass sämtlicher Clientcode neu übersetzt werden muss. Du kannst die Klasse nicht auf mehrere Header aufspalten. Du kriegst schlechter optimierten Maschinencode. Du hast sogar mehr Schreibaufwand. All das ist stumpf nicht notwendig.



  • @seldon

    Mal abgesehen von:

    Du kriegst schlechter optimierten Maschinencode

    hasst du technisch natürlich recht.

    Aber Hallo, wir sind beim normalen implementieren.

    Wenn du konsequent weiter denkst, gilt das was Du darlegst natürlich auch fuer alle privaten nicht virtuellen methoden ohne friend access !
    Wer macht private virtuelle methoden ???

    private deklarationen will man ja eigentlich per definition nicht weitergeben. Am liebsten soll man sie gar niemand sehen ^^
    Bei variablen hat man anders keine chance (allokation) als das sie im header stehen muessen.
    Aber statische private member haetten da nix zu suchen. Die kannst du auch alle mit dem selben aufwand was mir vorschlägst, durch lokale funktionen eliminieren.
    Warum macht man es da denn nicht ? Weil der Header durch die lokalen variablen eh versaut ist ?

    Ich denk es ist einfach uebersichtlicher, und die IDE's kommen damit besser klar bei der darstellung ...
    Und genau deswegen mach ich sowas auch, es ist einfach uebersichtlicher und bequemer, man kann dank tools besser navigieren, als wenn du zig private funktionen in einer cpp hasst.

    Woellte ich 100% information hiding, wuerd ich auch anders vorgehen. Aber das sind Arbeits/Implementationsdinge, kein öffentliches Interface ....

    Ciao ...



  • RHBaum schrieb:

    Wer macht private virtuelle methoden ???

    Ist bloss ein sehr übliches C++Idiom
    http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface


Anmelden zum Antworten