Projektaufbau - allgemeine Funktionen zuordnen



  • Hi Ihr 🙂

    Ich habe da mal eine Frage an euch.
    Was macht ihr in einem Projekt mit Funktionen, die ihr keiner Klasse zuordnen könnt? Verschiebt ihr die in eine Helperklasse und inkludiert diese überall, wo ihr diese Funktionen braucht. Definiert ihr diese Funktionen inline in einer globals.h??
    Was macht ihr damit? Was ist die schönste Lösung?

    Bin auf eure Antworten gespannt.

    Viele Grüße
    AndreaD



  • Hallo,

    also ich würde das immer in ein namespace verschieben
    und evtl. auch in einen eigenen Header, kommt halt darauf an,
    wie viele das sind (bei 2 rentiert sich das eher nicht).

    Gruß Simon



  • Funktion, die ich keiner Klasse zuordnen kann werden freie Funktionen und landen in einer eigenen .h/.cpp Datei. Oder mehreren, wenn ich die Funktionen irgendwie gruppieren kann.
    global.h heisst bei mir nix, denn der Name sagt nichts über den darin enthaltenen Inhalt aus.
    Globale Typdefinitionen liegen bei mir xyzTypeDef.h, wobei xyz ein Projektkürzel ist.
    Das Schlüsselwort inline benutze ich überhaupt nicht, da der Compiler besser weiss, was er inlinen soll und was nicht.



  • Verschiebt ihr die in eine Helperklasse

    Warum fuer normale Funktionen eine Dummyklasse erstellen. C++ ist nicht Java.

    Was ist die schönste Lösung?

    Die gibt es nicht. Haengt auch alles zu viel vom eigentlichen Problem ab.



  • Normalerweise haben solche Helperfunktionen bestimmte Klassen aus dem projekt als Argumente. In dem Fall gehören sie zum Interface der Klasse und in den entsprechenden Header. Ich habs bisher eher selten erlebt dass es so allgemeine Funktionen gibt die keinem bestimmten Kontext zuzuordnen waren.



  • pumuckl schrieb:

    Normalerweise haben solche Helperfunktionen bestimmte Klassen aus dem projekt als Argumente. In dem Fall gehören sie zum Interface der Klasse und in den entsprechenden Header. Ich habs bisher eher selten erlebt dass es so allgemeine Funktionen gibt die keinem bestimmten Kontext zuzuordnen waren.

    Ich schon, alleine schon wenn man erweiterte Funktionalität für Klassen aus anderen Bibliotheken bereitstellt. Okay, kontextlos sind die auch nicht, aber sie gehören sicher nicht in den gleichen Header wie die benutzte Klasse. Auch allgemeingültige Funktionen, die z.B. verschiedene Klassen als Parameter/Rückgabetyp verwenden, haben einen eigenen Header verdient.

    Oder wenn es sich wirklich um Standard-Dinge wie Runden, Zufallszahl generieren etc. handelt, wobei ich häufig verwendete Dinge mehr und mehr in eigene Bibliotheksheader auslagere.



  • Nexus schrieb:

    alleine schon wenn man erweiterte Funktionalität für Klassen aus anderen Bibliotheken bereitstellt. Okay, kontextlos sind die auch nicht, aber sie gehören sicher nicht in den gleichen Header wie die benutzte Klasse.

    Ebend, sie sind nicht kontextlos. In solchen Fällen schreibe ich einen "wrapper-header", wenn nicht gar eine Wrapperklasse. In dem Header wird die externe Klasse eingeführt sowie die erweiterte Funktionalität deklariert. Innerhalb des Projektes wird dann nurnoch der Header benutzt und nicht mehr das Original. Zumindest wenns tatsächlich so ist dass die Zusatzfunktionalität im ganzen Projekt benutzt wird und nicht nur an einer Stelle.

    Auch allgemeingültige Funktionen, die z.B. verschiedene Klassen als Parameter/Rückgabetyp verwenden, haben einen eigenen Header verdient.

    Wenns denn sowas gibt, ja. Ist mir aber wie gesagt bisher noch nicht wirklich untergekommen.

    Oder wenn es sich wirklich um Standard-Dinge wie Runden, Zufallszahl generieren etc. handelt, wobei ich häufig verwendete Dinge mehr und mehr in eigene Bibliotheksheader auslagere.

    Wie oben beschrieben würde ich die Dinge dann in einen myrandom- oder mymath-header packen, wo ich die restliche benutzte zufalls- bzw. mathefunktionalität gleich mit einbinde. Wenn ich den header immer paarweise mit einem anderen einbinden muss ist das meines erachtens eine Aufteilung von Funktionalität die nicht sinnvoll ist.



  • pumuckl schrieb:

    Auch allgemeingültige Funktionen, die z.B. verschiedene Klassen als Parameter/Rückgabetyp verwenden, haben einen eigenen Header verdient.

    Wenns denn sowas gibt, ja. Ist mir aber wie gesagt bisher noch nicht wirklich untergekommen.

    Wie? Das glaube ich dir nicht. 😉
    Vielleicht haben wir uns falsch verstanden, aber du wirst doch wohl ab und zu globale Funktionen haben, die auf mehreren Klassentypen operieren?

    Ansonsten stimme ich dir zu.



  • Nexus schrieb:

    Vielleicht haben wir uns falsch verstanden, aber du wirst doch wohl ab und zu globale Funktionen haben, die auf mehreren Klassentypen operieren?

    Nicht so dass sie
    a) überall im Projekt benutzt werden und
    b) nicht trotzdem dem Interface einer der beteiligten Klassen zuzuordnen wäre.

    Prominentes Beispiel für so eine globale Funktion auf mehreren (2) Klassentypen ist der op<< - arbeitet auf ostream und der jeweiligen Klasse, gehört aber ganz klar zum Interface der Klasse.



  • pumuckl schrieb:

    Nicht so dass sie
    a) überall im Projekt benutzt werden

    Okay, das kommt aber sowieso selten vor. Ein einzelner Header ist meiner Ansicht nach jedoch gerechtfertigt, sobald mehrere Dateien die darin enthaltene Funktionalität nutzen.

    pumuckl schrieb:

    b) nicht trotzdem dem Interface einer der beteiligten Klassen zuzuordnen wäre.

    Wenn du zwei fremde Klassen verwendest, kannst (oder solltest zumindest) du deren Header nicht verändern. Einen Wrapper-Header zu schreiben für etwas, das lange nicht überall benötigt wird, halte ich für unangebracht. Ausserdem kann es durchaus vorkommen, dass nicht unmittelbar klar ist, welcher Klasse eine Funktion "eher" angehört. Besonders, wenn es sich um ein Funktionstemplate handelt.

    pumuckl schrieb:

    Prominentes Beispiel für so eine globale Funktion auf mehreren (2) Klassentypen ist der op<< - arbeitet auf ostream und der jeweiligen Klasse, gehört aber ganz klar zum Interface der Klasse.

    Da hast du natürlich Recht, würde ich auch so machen. Bei einer fremden Klasse je nachdem ein Wrapper-Header...

    Hier so ein Beispiel aus einem meiner Projekte. Zwei überladene Funktionen berechnen das begrenzende Rechteck zweier Grafikobjekte. Es kommen drei Klassen aus der SFML-Bibliothek vor: FloatRect , Sprite und String .

    sf::FloatRect GetBoundingRect(const sf::Sprite& Sprite);
    sf::FloatRect GetBoundingRect(const sf::String& String);
    

    Bei keinem der drei Typen könnte ich sagen, dass die Funktionalität eindeutig zum Interface gehört. Also habe ich mir einen separaten Header erstellt, der ähnliche, auf Grafikobjekte bezogene Funktionen zusammenfasst. Und zwar ohne einen der verwendeten Klassenheader zu inkludieren - schliesslich braucht man als Anwender vielleicht nur ein paar der benötigten Typen.


Log in to reply