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



  • 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.



  • volkard schrieb:

    dann bleibt bei den bitmaps nur noch der grund, daß man default-konstruktoren überhaupt meiden sollte.

    Und woher kommt der Grund? Das klingt wie eine allgemeine Faustregel.

    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.

    Bitmaps kann man auch von Streams laden, den Dateinamen hast du zuerst ins Spiel gebracht :p
    Wie das allgemeine Schema von Bitmap in irgendeinem Fall ein größeres Performanceproblem darstellen kann, sehe ich aber gerade nicht. Allgemein haben dynamische Resourcen intern doch einfach einen Zeiger (in diesem Fall in einen std::vektor verpackt), der im Defaultkonstruktor unnötig genullt wird - damit das stört, muss man schon in einen _sehr_ kleinen Bereich gehen.

    ob du nen konstruktor oder ne ladefunktion baust, ist doch vom aufwand kein unterschied.

    Nein, aber vom Designstandpunkt aus IMHO schon. Dann muss man sich wohl überlegen, ob einem eine klare Aufgabentrennung ein paar Nullungen wert ist.

    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.

    Ich sage ja auch nicht, dass die STL perfekt ist - das Sequenzkonzept ist sicher in vielen Fällen nervig. Aber als Beispiel für klare Aufgabenverteilung und Datenkapselung ist sie nicht schlecht.



  • volkard schrieb:

    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.

    Nun, bisweilen kann man sich ja damit behelfen (je nach Können des Compilers):

    #include <algorithm>
    #include <vector>
    #include <list>
    
    template<class T, class A, template<class,class> class C>
    void sort(C<T,A>& c)
    {
    std::sort(c.begin(), c.end());
    }
    
    template<class T, class A>
    void sort(std::list<T,A>& c)
    {
    c.sort();
    }
    
    void foo()
    {
    std::vector<int> v;
    sort(v);
    std::list<int> l;
    sort(l);
    }
    


  • operator void schrieb:

    volkard schrieb:

    dann bleibt bei den bitmaps nur noch der grund, daß man default-konstruktoren überhaupt meiden sollte.

    Und woher kommt der Grund? Das klingt wie eine allgemeine Faustregel.

    Weil doch auch ein leeres Bitmap recht zeitintensiv sein kann.

    Es sei denn du erstellst im Default Ctor gar kein Bitmap sondern lässt das Objekt in einem 'nicht vorhanden'-status. Das wäre natürlich auch sehr schlecht.



  • DrGreenthumb schrieb:

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

    Geht natürlich.



  • ?!?!? schrieb:

    DrGreenthumb schrieb:

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

    Geht natürlich.

    Doch nicht. lol



  • Shade Of Mine schrieb:

    Weil doch auch ein leeres Bitmap recht zeitintensiv sein kann.

    Es sei denn du erstellst im Default Ctor gar kein Bitmap sondern lässt das Objekt in einem 'nicht vorhanden'-status. Das wäre natürlich auch sehr schlecht.

    Dass es so sein _kann_ ist aber keine Begründung dafür, Default-Konstruktoren allgemein zu meiden - darauf zielte meine Frage ja ab. (Siehe volkards Originalposting.)
    Um meine Bitmap als Beispiel totzutreten, der Default-Konstruktor setzt width und height (unsigneds) auf 0 und der pixels-Vektor wird default-konstruiert. (Bei Bedarf könnte man den Vektor sogar noch durch was Sparsameres ersetzen.)
    -> Alle Klasseninvarianten erfüllt (ohne magische Flags), kein Overhead der im normalen Umfeld einer Bitmap relevant ist. Ich sehe nach wie vor kein Problem 🙄



  • Um überhaupt noch beim Fachsimpeln ein WENIG mitreden zu können. In Java benutze ich fast nie def ctors. Liegt aber einfach daran, daß ich meine Klassen in der Regel fast immer Daten von außen von Nöten sind. Hat jetzt aber echt nichts mit Performance zutun. 😉



  • Shade Of Mine schrieb:

    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 hab nie selbst einen Hash implementiert (auch nie wirklich benutzt; sprich ich hab kaum Ahnung davon, was ein Hash ist), aber dast klingt do so, aus bräuchte man nur eine einzige Funktion do_hash(), die genau das zurueckliefert, was h.value() zurueckliefern wuerde. 😕

    Ich versteh jetzt also nicht, was an meiner Denkweise falsch ist (vielleicht kannst du's ja an einem anderen Beispiel erklaeren):

    Ideel: wenn Funktionen gemeinsame Daten bearbeiten, scheinen sie zusammenzugehoeren. Ob jetzt nur die gemeinsamen Daten oder Daten & Funktionen zusammen eine Einheit (Klasse) bilden, darueber koennte man dann streiten

    Praktisch: lieber als x Funktionen die selben 4 Argumente mitzugeben, pack ich alles zusammen in eine Klasse, die jene 4 Werte als Ctor-Argumente erhaelt, das ist uebersichtlicher und IMO eine bessere Loesung als z. B. globale Varialben

    Korrigiert & kritisiert mich, wenn ich mit dieser Meinung total daneben liege 🙂

    @Wan-Hi: wenn du keine Default-Konstruktoren hast, wie legst du dann Arrays von Objekten an?



  • Blue-Tiger schrieb:

    Ich hab nie selbst einen Hash implementiert (auch nie wirklich benutzt; sprich ich hab kaum Ahnung davon, was ein Hash ist), aber dast klingt do so, aus bräuchte man nur eine einzige Funktion do_hash(), die genau das zurueckliefert, was h.value() zurueckliefern wuerde. 😕

    OK, das Beispiel war nicht super - aber so eine Hash (oder war es MD5?) Klasse gibt es wirklich. Sie wird sogar verwendet... 😞

    Natürlich reicht hier eine Funktion. Aber was würdest du machen wenn es 3 Funktionen gäbe?
    do_hash
    un_hash (OK, gibts nicht, ist aber nur n Beispiel)
    invert (Wozu auch immer ;))

    OK, mir fällt nichts besseres ein.

    Im Prinzip meine ich damit: nur weil etwas zusammengehört, gehört es noch lange nicht in eine Klasse.

    Ich versteh jetzt also nicht, was an meiner Denkweise falsch ist (vielleicht kannst du's ja an einem anderen Beispiel erklaeren):

    Ich weiss nicht ob deine Denkweise falsch ist - ich meine nur, dass es kritisch sein kann, wenn du deine Aussage zu ernst nimmst.

    Ideel: wenn Funktionen gemeinsame Daten bearbeiten, scheinen sie zusammenzugehoeren. Ob jetzt nur die gemeinsamen Daten oder Daten & Funktionen zusammen eine Einheit (Klasse) bilden, darueber koennte man dann streiten

    Manchmal - aber oft macht eine Klasse keinen sinn, wie bei meinem verunglückten Hash Beispiel.

    Praktisch: lieber als x Funktionen die selben 4 Argumente mitzugeben, pack ich alles zusammen in eine Klasse, die jene 4 Werte als Ctor-Argumente erhaelt, das ist uebersichtlicher und IMO eine bessere Loesung als z. B. globale Varialben

    Aber dadurch musst du kein Objekt haben.
    zB
    get_mwst()
    get_kest()
    get_wasweissich()

    sind auch sehr ähnlich. Sie geben alle einen Steuersatz basierend auf ähnlichen Daten aus. Dennoch passen sie nicht in eine Klasse. Weil sie zwar zusammengehören, aber keinen 'state' haben. Und 'stateless' Objekte machen idR keinen Sinn.

    @operator void:
    du hast mindestens die Kosten einer sinnlosen allokierung.
    Klar, so viel ist es nicht - aber es sind dennoch sinnlose kosten. Weil du von vornherein weisst, dass du die Defaultwerte sowieso wegschmeisst.

    Du gibst einen Text ja auch nicht zum probelesen weg, wenn du weisst, dass du ihn sowieso neu schreibst, oder ? 😉



  • Shade Of Mine schrieb:

    Ideel: wenn Funktionen gemeinsame Daten bearbeiten, scheinen sie zusammenzugehoeren. Ob jetzt nur die gemeinsamen Daten oder Daten & Funktionen zusammen eine Einheit (Klasse) bilden, darueber koennte man dann streiten

    Manchmal - aber oft macht eine Klasse keinen sinn, wie bei meinem verunglückten Hash Beispiel.

    Praktisch: lieber als x Funktionen die selben 4 Argumente mitzugeben, pack ich alles zusammen in eine Klasse, die jene 4 Werte als Ctor-Argumente erhaelt, das ist uebersichtlicher und IMO eine bessere Loesung als z. B. globale Varialben

    Aber dadurch musst du kein Objekt haben.
    zB
    get_mwst()
    get_kest()
    get_wasweissich()

    sind auch sehr ähnlich. Sie geben alle einen Steuersatz basierend auf ähnlichen Daten aus. Dennoch passen sie nicht in eine Klasse. Weil sie zwar zusammengehören, aber keinen 'state' haben. Und 'stateless' Objekte machen idR keinen Sinn.

    Ich glaube, damit waren eher set-Funktionen gemeint, um die Invarianten zu bewaren, oder habe ich ihn da falsch verstanden?



  • Shade Of Mine schrieb:

    du hast mindestens die Kosten einer sinnlosen allokierung.

    Allokiert std::vector zwangsweise etwas? Na ja, wie gesagt. Den könnte man durch was Sparsameres ersetzen, wenn es Bedarf gäbe; wenn die Bitmap leer ist, kann der "Datenzeiger" ja ruhig 0 sein. Bitmap::Bitmap() müsste dann nur 12 Bytes auf 0 setzen. (width, height, pixel-Zeiger.)

    Ich komme immer noch nicht dahinter, wie man sich davon beim Design beeinflussen lassen kann - aber von mir aus können wir uns auf unterschiedliche Optimierungs-Grundhaltungen einigen, oder sowas, ich glaube nicht, dass wir hier noch weiter kommen 🙂



  • man macht keine default-konstrutoren, wenn sie keine bedeutung haben. man vererbt auch nicht, wenn die vererbung keine bedeutung hat. default-konstruktoren sind oft schlecht, weil sie oft sachen konstruieren, die es gar nicht gibt. als oberschwachsinnigstes beispiel nenne ich hier mal eine bitmap, die nicht geladen ist. mir tut es leid, wenn ihr nubes euch von schlechten libs einladen laßt, es noch schlechter zu machen. warum kann man ifstreams anlegen, ohne nen dateinamen anzugeben? das ist doch auch schwachsinn. wenn man ne datei öffnen wil, die es nicht gibt, fliegt ne exception. so muß ich bei jeder einzelnen verwendung schreiben ifstream in(filename); if(!in) throw FileOpenError(filename);. und zufällig gibts sogar noch performanceargumente gegen beide schwachsinnigkeiten (also bitmap, die es nicht gibt und file, das es nicht gibt). und was höre ich? ich höre "ach, kann ja gar nicht sein. deine argumente will ich nicht verstehen und die performanceeinbuße ist gering".
    hau dir bitte mal mit nem brett vor den kopp, das hilft bei sowas.



  • operator void schrieb:

    Allokiert std::vector zwangsweise etwas? Na ja, wie gesagt. Den könnte man durch was Sparsameres ersetzen, wenn es Bedarf gäbe; wenn die Bitmap leer ist, kann der "Datenzeiger" ja ruhig 0 sein. Bitmap::Bitmap() müsste dann nur 12 Bytes auf 0 setzen. (width, height, pixel-Zeiger.)

    was passiert, wenn in deiner grafik-engine das raumschiff gemalt werden soll, aber ne ungeladenen bitmap zu verfügung steht?
    a) es wird ignoriert (mit nem if im kerncode).
    b) die kacke stürzt ab wegen zugriff auf 0
    c) die kacke geht raus wegen division by zero beim transformieren vin breite 0 auf darstelungsbreite
    d) egal, die lib (d3d oder ogl) wirds schon fressen, bunte effekte mag ich eh

    würdest du aber fein programmieren, wäre die frage gar nicht existent.

    a) es gibt keine uneladenen bitmaps. der ctor schmeißt ne exception, wenn was nicht klapt.

    Ich komme immer noch nicht dahinter, wie man sich davon beim Design beeinflussen lassen kann - aber von mir aus können wir uns auf unterschiedliche Optimierungs-Grundhaltungen einigen, oder sowas, ich glaube nicht, dass wir hier noch weiter kommen 🙂

    probier's mal mit unserem scheiß-design. könnte ja sein, daß es süchtig macht.



  • Dass leere Bitmaps als so exotisch empfunden werden, hätte ich gar nicht gedacht. Für mich sind Bitmaps einfach zweidimensionale Container von Pixeln - da ist eine Größe von Null Quadratpixeln IMHO kein exotischer Sonderfall. Genau wie es leere Strings und leere Vektoren gibt. Ich habe mich eher von deren Design leiten lassen als von den IOStreams, die finde ich nämlich auch gruselig.

    Wenn die Klasse dadurch mit vielen if()s oder gar einem bool-Flag verseucht wäre, würde ich mir Sorgen machen, aber genau das tritt ja nicht auf. Wenn ich leere Bitmaps verhindern wollte, bräuchte ich dagegen die if()s. (Wobei die natürlich auch sehr eingedämmt und damit kein Problem wären - aber trotzdem.)

    volkard schrieb:

    was passiert, wenn in deiner grafik-engine das raumschiff gemalt werden soll, aber ne ungeladenen bitmap zu verfügung steht?
    a) es wird ignoriert (mit nem if im kerncode).
    b) die kacke stürzt ab wegen zugriff auf 0
    c) die kacke geht raus wegen division by zero beim transformieren vin breite 0 auf darstelungsbreite
    d) egal, die lib (d3d oder ogl) wirds schon fressen, bunte effekte mag ich eh

    a) Kein if nötig, denn
    b) wer getPixel() mit x>=width oder y>=height aufruft, hat in jedem Fall ein Problem.
    c und d) Bitmap hat erstmal nichts mit D3D oder OGL zu tun. Es werden auch viele unterwegs erstellt und bei weitem nicht alle aus Dateien geladen.

    probier's mal mit unserem scheiß-design. könnte ja sein, daß es süchtig macht.

    Tut mir ja Leid, dass meine Kristallkugel im Keller steht und ich die Motivation für euer Design nicht sofort gesehen habe. Vielleicht hättest du auch darauf hinweisen können, bevor du deinen speziellen Charme ausgepackt hast 🙄 Ich sehe jedenfalls nur lange Diskussionen über die Performance und die unbegründete Defaultkonstruktoren-sind-böse-Regel, nach deren Erklärung ich sogar gefragt hatte. Die hättest du auch sachlich bringen können.



  • würdest du denn beim nächsten mal bitmaps wieder mit nem default-ctor aufrüsten?



  • Volkard: wenn du keinen Default Ctor hast, wie legst du dann Arrays von Objekten an? (Bitte nicht hauen wenn ich jetzt eine super, super dumme Frage gestellt hab 😞 )



  • Blue-Tiger schrieb:

    Volkard: wenn du keinen Default Ctor hast, wie legst du dann Arrays von Objekten an? (Bitte nicht hauen wenn ich jetzt eine super, super dumme Frage gestellt hab 😞 )

    ich hau die mit .push_back in nen std::vector rein.
    oder ich hab eh im array bloß zeiger auf die objekte.


Anmelden zum Antworten