Verständnisfrage Funktion vs Klasse



  • Hallo zusammen,

    ich tu mir mit C++ noch etwas schwer. Eine grundsätzliche Frage beschäftigt mich, und zwar den Moment, eine Klasse zu erzeugen oder einfach mehrere Funktionen zu verwenden.

    Wenn ich z.B. eine Funktion mit mehreren Unterfunktionen habe, und ich nicht mehr als eine Instanz brauche, macht das dann noch Sinn aus der Funktion mit ihren Unterfunktionen eine eigene Klasse zu bilden ?



  • Die Frage ist, wie deine Funktionen aussehen. Wenn deine Funktionen immer auf den selben Daten arbeiten, macht es Sinn sich zu überlegen ob man sie in eine Klasse packt. Eine Klasse ist ja einfach nur eine Zusammenfassung von Daten und Funktionen (die auf den Daten operieren).



  • Ich mache das immer in etwa so: Wenn's unklar ist, ob es eine Klasse oder Funktions-Sammlung werden soll, werden es immer erst einzelne Funktionen. Wenn ich dann beim Benutzen den Funktionen merke, dass eine Klasse doch eleganter/angenehmer/besser/insgesamt-positiver wäre, wird halt eine Klasse draus gemacht.
    Es gibt dafür keine klaren Regeln und zusätzlich zu Klassen gibt's auch noch Namensräume, um Funktionalitäten zu kapseln.

    Also einfach nach Gefühl, ein "falsch" gibt es eigentlich nicht, nur ein "weniger schön". Und den ganzen Krams sollte man auch versuchen aus der Sicht des "Benutzers" zu sehen, also desjenigen, der die Funktionen/Klassen/Namensräume anwendet und nicht (nur) als derjenige, der sie implementiert.



  • Hi,

    also bei mir entscheidet sich sowas erstmal an der Frage: "Gibt es ein Ding, mit dem etwas passiert?" (und das einen definierten Zustand/Eigenschaften hat)
    So komme ich zuerst auf "fachliche Objekte". Nähere Ausdifferenzierung führt dann oftmals zu einem "Umschneiden" (nicht selten sind "Objekte der realen Welt" schlechte Kandidaten für "Programmierobjekte") auf fachlicher Ebene. Das Ganze hat erstmal noch nichts mit Technik oder Programmiersprache zu tun, sondern beschreibt erstmal nur, "wer was mit wem tut".
    (später kommen dann über Implementierungstechniken, Sprachmittel, Infrastrukturaufgaben, ... haufenweise "technische Objekte" dazu)

    Wenn etwas dagegen einen Ablauf/Algorithmus darstellt, ist es für mich erstmal ein Kandidat für eine Funktion.

    (Übrigens schließe ich mich der Definition von Sutter (? oder war es Meyers ? Ich bringe die Beiden immer durcheinander) an, nach der auch freie Funktionen Bestandteil einer Klassenschnittstelle sein können, wenn sie im Wesentlichen zur Manipulation/Handling dieser Klasse dienen).

    Also kurz gesagt:
    "Ding" -> Objekt
    "Ablauf" -> Funktion

    Gruß,

    Simon2.



  • Simon2 schrieb:

    (Übrigens schließe ich mich der Definition von Sutter (? oder war es Meyers ? Ich bringe die Beiden immer durcheinander) an, nach der auch freie Funktionen Bestandteil einer Klassenschnittstelle sein können, wenn sie im Wesentlichen zur Manipulation/Handling dieser Klasse dienen).

    Wobei es hier wieder einige Streitfälle gibt. Im Grunde genommen sind bei vielen Anwendungsfällen freie Funktionen und Memberfunktionen nahezu gleichwertig, man muss sich halt entscheiden, was besser ins Konzept passt.

    Ein Beispiel wäre eine Vektorklasse und eine Betragsfunktion Norm() . Eigentlich könnte man diese als Memberfunktion schreiben, allerdings hat man dann bei zusammengesetzten Ausdrücken etwas (meiner Ansicht nach) weniger Schönes:

    (Vector1 + 4*Vector2).Norm();
    

    In diesem Falle würde ich also eher zu freien Funktionen tendieren, zumal die Norm ja nicht direkt für die Instanz eines Vektors benötigt wird.

    Norm(Vector1 + 4*Vector2);
    

    Aber eben, da gibt es auch viele Fälle, wo das nicht so eindeutig ist. Wenn ich mir nicht sicher bin, überlege ich mir, ob die Funktion für ein Objekt selber erforderlich ist (weil sie z.B. auf private Member zugreift), oder ob sie einfach unterstützende Wirkung von aussen besitzt.

    Für den Fall, wo man gar nicht wirklich ein Objekt hat, lohnt sich vielleicht eine freie Funktionssammlung mehr. Da gibt es wie gesagt noch Namespaces, das finde ich auch schöner als zum Beispiel eine Klasse nur mit statischen Funktionen. Da würde ich es wie Badestrand machen und ein wenig ausprobieren, mit der Zeit zeigt sich dann meistens, was am praktischsten ist.



  • Hallo zusammen,

    vielen Dank für eure Tips, damit ist mir die Sache schon viel klarer geworden !



  • Scott Meyers hat für die Thematik mal ein paar Regeln aufgestellt, an die man sich gut halten kann:

    Effective C++, Scott Meyers schrieb:

    • Virtual functions must be members. If f needs to be virtual, make it a member function of C.
    • operator>> and operator<< are never members. If f is operator>> or operator<<, make f a non-member function. If, in addition, f needs access to non-public members of C, make f a friend of C.
    • Only non-member functions get type conversions on their left-most argument. If f needs type conversions on its left-most argument, make f a non-member function.
    • If, in addition, f needs access to non-public members of C, make f a friend of C.
    • Everything else should be a member function. If none of the other cases apply, make f a member function of C.


  • Grundsätzlich bin ich immer ein wenig skeptisch gegenüber solchen Regeln, die Anspruch auf "richtiges Programmieren" haben. Wie gesagt gibt es meines Erachtens auch Grenzfälle - man kann nicht kategorisch sagen, was wo besser ist.

    Beispiel ist der folgende Punkt, wird der auch irgendwie gerechtfertigt? "are never members" tönt für mich nicht wie ein gutes Argument...

    Tachyon schrieb:

    • operator>> and operator<< are never members. If f is operator>> or operator<<, make f a non-member function. If, in addition, f needs access to non-public members of C, make f a friend of C.


  • Nexus schrieb:

    Beispiel ist der folgende Punkt, wird der auch irgendwie gerechtfertigt? "are never members" tönt für mich nicht wie ein gutes Argument...

    Tachyon schrieb:

    • operator>> and operator<< are never members. If f is operator>> or operator<<, make f a non-member function. If, in addition, f needs access to non-public members of C, make f a friend of C.

    Wenn du für eine Klasse Foo den operator<< z.B. für einen Stream (std::ostream) nicht global implementieren möchtest, dann müsstest du die Lib-Klasse ostream editieren. Ziemlich unschön und oftmals sogar nahezu unmöglich (für Nicht-Template Klassen, deren Implementierung in object files liegen).



  • this->that schrieb:

    Wenn du für eine Klasse Foo den operator<< z.B. für einen Stream (std::ostream) nicht global implementieren möchtest, dann müsstest du die Klasse Lib-Klasse ostream editieren. Ziemlich unschön, oder (und oftmals sogar unmöglich)?

    Ja, das ist mir schon klar. Im Text steht aber ausdrücklich, dass operator>> und operator<< nie Member wären. Auch wenn es sich nicht um std::ostream -Operatoren handelt...


Anmelden zum Antworten