Eine kleine Umfrage: C/C++ the OOP way?



  • Blue-Tiger schrieb:

    im Allgemeinen steckt bei mir (fast) alles in Klassen. Oft passierts mir z. B., dass 3 oder 4 Funktionen auf die gleichen Variablen zugreifen muessen, das endet dann meist in einer Klasse mit den Variablen als Membern und den Funktionen als Methoden 🙂

    halte ich für fragwürdig.

    denn ergibt das dann auch ein Objekt?
    oder ist es dann sowas:

    Hash h;
    h.do_hash("abc");
    return h.value();
    


  • Ich benutze sehr viele Klassen und arbeite sehr OO. Aber ich habe auch einige kleinere Hilfsfunktionen.



  • "One class - one responsibility" ist IMHO schon mal ein sehr guter Anfang.
    Ich habe z.B. eine Bitmap-Klasse, die wirklich nur setPixel, getPixel, width, height, resize und zwei Hilfsfunktionen (fill und replace) anbietet. Die Zugriffe auf die internen Daten sind damit auf ein Minimum eingedämmt. Alles weitere (drawText, loadFromBMP, saveToPNG usw. etc.) sind freie Funktionen. Das finden manche Ruby-Coder dann zwar total anti-OO, weil man beim Aufrufen keinen .-Operator braucht, aber IMHO gehört zu guter OO nicht nur die schicke Syntax, sondern auch Kapselung und klare Aufgabenverteilung. (Anderes Beispiel dafür wären die STL-Container und -Algorithmen.)

    Ich bin also dafür, sich klar zu machen, dass freie Funktionen nicht beißen 😉



  • operator void schrieb:

    Alles weitere (drawText, loadFromBMP, saveToPNG usw. etc.) sind freie Funktionen. Das finden manche Ruby-Coder dann zwar total anti-OO, weil man beim Aufrufen keinen .-Operator braucht, aber IMHO gehört zu guter OO nicht nur die schicke Syntax, sondern auch Kapselung und klare Aufgabenverteilung. (Anderes Beispiel dafür wären die STL-Container und -Algorithmen.)

    Ich bin also dafür, sich klar zu machen, dass freie Funktionen nicht beißen 😉

    Full ACK



  • operator void schrieb:

    "One class - one responsibility" ist IMHO schon mal ein sehr guter Anfang.

    jo.

    Ich habe z.B. eine Bitmap-Klasse, die wirklich nur setPixel, getPixel, width, height, resize und zwei Hilfsfunktionen (fill und replace) anbietet. Die Zugriffe auf die internen Daten sind damit auf ein Minimum eingedämmt.

    sehr fein. das machen die wenigsten und kommen dann mit klassen an, die niemals zu kapieren sind (und niemals zu heilen, falls sich doch ein designfehler eingeschlichen hat, was man nie wirklich vermeiden kann).

    Alles weitere (drawText, loadFromBMP, saveToPNG usw. etc.) sind freie Funktionen.

    überhaupt gar kein ack. loadFromBMP klingt für mich stark danach, als sollte das ein ctor sein. ich zeige mal ein paar fehlerhafte implementierungen (weiß ja nicht, welche du gewählt hast):

    //mit leerem default-ctor
    Bitmap b;//uninitialisiert, dangerous
    loadFromBmp(b,"test.bmp");//referenz zweckentfremdet
    //by throw in laodFromBotmap ein abkacker, weil b nicht löschbar
    

    der leere default-ctor ist einfach zu gefährlich. sagen wir mal, der verbietet sich.

    //mit default-ctor, der objekt löschbar macht
    Bitmap b;//zeitverschwendung
    loadFromBmp(&b,"test.bmp");//ok
    

    die zeitverschwendung, b erst löschbar zu machen und dann doch was anderes reinzumachen, ist doch doof. sagen wir mal, die verbietet sich, weil wir auch sehr schnellen code haben wollen (deshalb verbieten sich für mich ja auch pimpl und rimpl).

    Bitmap *b=loadFromBmp("test.bmp");//zeitverschwendung
    

    offensichtlich passiert ein new in loadBitmap, aber das ist ein new, das ich nicht brauche.

    ich frage mich, wie du es irgendwie performant und halbwegs ehrenhaft hinkriegen magst mit deinen globalen funktionen.

    Bitmap b("test.bmp");//bitmap kann zu viel, sonst aber perfekt.
    
    FileBitmap b("test.bmp");//ok, thema ist durch
    

    Das finden manche Ruby-Coder dann zwar total anti-OO, weil man beim Aufrufen keinen .-Operator braucht, aber IMHO gehört zu guter OO nicht nur die schicke Syntax, sondern auch Kapselung und klare Aufgabenverteilung. (Anderes Beispiel dafür wären die STL-Container und -Algorithmen.)

    ja, es ist ne gute einsicht, wenn man kapiert, daß fopen, fclose fget und die ganzen c-sachen, die ein FILE-objekt benutzen, sauber und gut oo sind.
    die stl-algos sind es weniger, aber algos rufen auch nicht immer danach, oo zu sein.

    Ich bin also dafür, sich klar zu machen, dass freie Funktionen nicht beißen 😉

    freie konstruktoren beißen aber. ätsch.



  • pimpl? rimpl? hör ich heute zum 1. mal...is das pointer implement und reference implement?

    "One class - one responsibility" ist IMHO schon mal ein sehr guter Anfang.

    mit anderen worten: versuch nie eine Klasse zu schaffen, die objekte effizient verwaltet, und gleichzeitig spezielle funktionen für diese objekte bietet?



  • otze schrieb:

    pimpl? rimpl? hör ich heute zum 1. mal...is das pointer implement und reference implement?

    pointer to implemetation. jo.
    "pimpl-idiom" oder "pimpl" ist eines von herb sutters lieblingsworten. siehe lektion 26ff aus exceptions c++". rimpl gibts nur während der laufzeit dieses threads, hofe ich.

    mit anderen worten: versuch nie eine Klasse zu schaffen, die objekte effizient verwaltet, und gleichzeitig spezielle funktionen für diese objekte bietet?

    unter anderem auch das. eigentlich eher "versuch nie eine Klasse zu schaffen, die effizente objektverwaltung implementiert , und gleichzeitig spezielle funktionen für diese objekte implementiert"
    natürlich kann die eine klasse das eine implemetieren, die andere klasse das andere und dazu das eine benutzen. und sogar manchmal das eine öffentlich zur verfügung stellen. dann kann die klasse das eine und das andere. zum beispiel effizient objekte verwalten und spezielle funktionen anbieten.



  • volkard schrieb:

    otze schrieb:

    pimpl? rimpl? hör ich heute zum 1. mal...is das pointer implement und reference implement?

    pointer to implemetation. jo.
    "pimpl-idiom" oder "pimpl" ist eines von herb sutters lieblingsworten. siehe lektion 26ff aus exceptions c++". rimpl gibts nur während der laufzeit dieses threads, hofe ich.

    kann man sich das buch legal downloaden, oder muss das wie der struppi und der standard auch auf meine liste der lesenswerten Bücher? 🙄[exceptions c++=exceptional c++?]

    mit anderen worten: versuch nie eine Klasse zu schaffen, die objekte effizient verwaltet, und gleichzeitig spezielle funktionen für diese objekte bietet?

    unter anderem auch das. eigentlich eher "versuch nie eine Klasse zu schaffen, die effizente objektverwaltung implementiert , und gleichzeitig spezielle funktionen für diese objekte implementiert"
    natürlich kann die eine klasse das eine implemetieren, die andere klasse das andere und dazu das eine benutzen. und sogar manchmal das eine öffentlich zur verfügung stellen. dann kann die klasse das eine und das andere. zum beispiel effizient objekte verwalten und spezielle funktionen anbieten.

    1.wieder was gelernt
    2. jetzt weis ich, wieso ich mit meiner letzten schandtat nich zufrieden bin^^



  • kann man sich das buch legal downloaden, oder muss das wie der struppi und der standard auch auf meine liste der lesenswerten Bücher? [exceptions c++=exceptional c++?]

    ne, musst du kaufen. Aber lohnt sich definitiv.

    btw. den Standard lesen, lohnt sich nicht wirklich. Den kannst du zum nachschlagen benutzen, wenn du mal im C++ Forum oder im Usenet den Obermaker raushängen lassen willst 😉



  • lesenswert schon, aber nicht kaufenswert wie ecp und struppi. wenn man exceptional c++ durchgelesen hat, muß man es eigentlich nie wieder aufschlagen, also müßte es reichen, es sich in der bücherei auszuleihen.



  • //mit default-ctor, der objekt löschbar macht
    Bitmap b;//zeitverschwendung
    loadFromBmp(&b,"test.bmp");//ok
    

    die zeitverschwendung, b erst löschbar zu machen und dann doch was anderes reinzumachen, ist doch doof. sagen wir mal, die verbietet sich, weil wir auch sehr schnellen code haben wollen (deshalb verbieten sich für mich ja auch pimpl und rimpl).

    Jup, das sieht meinem Code am ähnlichsten.
    Das Löschbarmachen ist in diesem Fall der Defaultkonstruktor eines Vektors - klar ist das unnötig, aber im Vergleich zum Öffnen und Parsen einer kompletten Datei doch absolut vernachlässigbar... Da geht bei mir das Design vor und für jeden Dateitypen einen Konstruktor hinzuzufügen finde ich nicht sehr elegant.

    die stl-algos sind es weniger, aber algos rufen auch nicht immer danach, oo zu sein.

    Die Container sind IMHO gute OO, eben weil die Algos ausgelagert sind. In anderen Sprachen haben Containerklassen einen Haufen Methoden (die alle Zugriff auf die Interna haben) und dadurch auch einen viel zu großen Aufgabenbereich.



  • volkard schrieb:

    Alles weitere (drawText, loadFromBMP, saveToPNG usw. etc.) sind freie Funktionen.

    überhaupt gar kein ack. loadFromBMP klingt für mich stark danach, als sollte das ein ctor sein.

    ich dachte da eher mehr an

    Bitmap b(loadFromBMP("nix.bmp"));
    

    da könnte Bitmap nen Ctor für rohe daten haben - loadFrom* ladet die Datei und liefert die Rohen daten zurück.

    Man hätte somit eine Art BitmapHandle - das in loadFrom* erstellt wird und in Bitmap einfach übernommen wird.

    Wäre soetwas OK?



  • Shade Of Mine schrieb:

    ich dachte da eher mehr an

    Bitmap b(loadFromBMP("nix.bmp"));
    

    da könnte Bitmap nen Ctor für rohe daten haben - loadFrom* ladet die Datei und liefert die Rohen daten zurück.

    Man hätte somit eine Art BitmapHandle - das in loadFrom* erstellt wird und in Bitmap einfach übernommen wird.

    Wäre soetwas OK?

    Das was du jetzt Bitmap-Handle nennst, wäre dann ja quasi das eigentliche Bitmap-Objekt.

    Da finde ich Volkards Ansatz von Bitmap und FileBitmap besser.



  • DrGreenthumb schrieb:

    Da finde ich Volkards Ansatz von Bitmap und FileBitmap besser.

    Nur hat man da das Problem, dass man Polymorphie braucht um beliebige Dateien (Datei Typen) zu laden.



  • typedef unsigned char byte_t;
    
    class bitmap {
      byte_t *data_m;
    public:
      template<class Loader>
      bitmap(const char *str) : data_m(Loader(str)) { }
      ~bitmap() { delete []data_m; }
    };
    
    byte_t *bmp_loader(const char *str) { /*...*/ return 0x0; }
    
    int main() {
      bitmap bit<bmp_loader>("demo.bmp");
    }
    

    ?



  • Konstruktor mit Template-Argument geht leider nicht. Stolper ich auch immer wieder drüber 😞



  • ach verdammt (btw. das wär was für langX ;))



  • wär zwar nichts für container, aber mithilfe eines 2. parameters sollte es doch gehen oder?
    oder ner static methode, welche es erlaubt, den loader im voraus festzulegen, aber das wär wiederum nichts, wenns ums schnelle einfügen geht...
    3. möglichkeit wär natürlich, dass der teil, welcher die datei ausliest, je nachdem welcher typ das ist, einen weiteren char vorpackt, und man dann intern einfach nen switch hat, aber das wär ja fast dasselbe wie die erste möglichkeit. Ich glauba n dieser stelle kommt man wohl nicht an der polymorphie vorbei, wenn mans "schön" machen will



  • operator void schrieb:

    klar ist das unnötig, aber im Vergleich zum Öffnen und Parsen einer kompletten Datei doch absolut vernachlässigbar...

    ja, bei den bitmaps kannste in sachen performance hudeln wie du magst. einmal detei-öffnen und du hast eh schon 100000000 takte weg. wozu hier und da 100 sparen? ist hier völlig unnötig.
    dann bleibt bei den bitmaps nur noch der grund, daß man default-konstruktoren überhaupt meiden sollte.
    bei anderen klassen, die vielleicht nicht von nem filename, sondern von einem bereits offenen istream& erzeugt/geladen werden, kann das mit der performance schon ganz anders aussehen.

    [quote] Da geht bei mir das Design vor und für jeden Dateitypen einen Konstruktor hinzuzufügen finde ich nicht sehr elegant.[quote]
    ob du nen konstruktor oder ne ladefunktion baust, ist doch vom aufwand kein unterschied.

    Die Container sind IMHO gute OO, eben weil die Algos ausgelagert sind. In anderen Sprachen haben Containerklassen einen Haufen Methoden (die alle Zugriff auf die Interna haben) und dadurch auch einen viel zu großen Aufgabenbereich.

    naja, aber ich *denke* sachen wie "und dann sortiere ich die liste" aber ich *schreibe* NICHT "list.sort()" oder das gleichwertige "sort(&list)", sondern einen unfug wie "sort(list.begin(),list.end())". sollte ich wirklich *gedacht* haben "und dann sortiere ich mal den bereich vom anfang der liste bis zum ende der liste". nee, dazu sind meine drogen gar nicht gut genug.



  • kingruedi schrieb:

    bmp_loader...

    eigentlich nicht.
    aber ist auch unerheblich. hätte nicht gedacht, daß ihr so konkrete (und gute) vorschläge macht, wie es weitergehen würde.
    vermutlich isses wichtig, sich erstmal klar zu werden, was ne Bitmap, die jeder anfassen kann, sein soll. vermutlich doch die klasse, die auch sich laden kann. dann müßte man halt FileBitmap zu Bitmap umbenennen, nachdem man Bitmap zu BitmapData /Canvas/Plane/Pixelbuffer... umgenannt hat.


Anmelden zum Antworten