Objektorientierte Klassenstruktur für Zeichenprogramm - Änfängerproblem



  • Hallo gamer804,

    oh wow, danke für den Beispielcode!

    Das muss ich mir erst einmal in Ruhe anschauen und geistig aufnehmen - bin wie gesagt noch Anfänger.

    Danke und Grüße,
    Bernd



  • Hallo gamer804,

    oh wow, danke für den Beispielcode!

    Das muss ich mir erst einmal in Ruhe anschauen und geistig aufnehmen - bin wie gesagt noch Anfänger.

    Danke und Grüße,
    Bernd

    bitte, ist einfach eben schnell runtergetippt und nicht getestet, aber ich denke es ist leicht verständlich, wenn nicht, frag. 🙂
    Ist nicht die beste lösung aber eine der einfachsten würde ich sagen, musste mal gucken ob das jetzt genau auf dein projekt passt, weil naja, hast ja nicht so viele infos gesagt.

    Nicht böse gemeint, aber diese Präfixe stören absolut den Lesefluss

    😃 Sorry, ich hab übrigens mich von euch überzeugen lassen und hab aus meinem gesamten aktuellen projekt die prefixe komplett entfernt 😉
    ich dachte aber dieses mal mache ich es noch einmal, weil es dann einfacher zu verstehen (wenn auch nicht zu lesen) ist 😉



  • @mireiner: Vergiss gamer8o4s Code am besten schnell wieder. Da drin sind so viel schlechter C++-Stil und Fehler, das schadet mehr als es nützt.

    Nimm das bitte nicht persönlich, gamer8o4, aber auch abgesehen von den Präfixen ist der Code ein schlechtes Beispiel.

    Zum Beispiel könntest du die Konstruktor-Initialisierungsliste verwenden. Und ein color -Typedef für eine Farbkomponente (nicht Farbe) ist fragwürdig. Ebenso, wieso du einmal float und einmal unsigned char verwendest, und ebenso die Defaultparameter (bis auf den letzten). Der Konstruktor sähe besser so aus:

    Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 255)
    : r(r)
    , g(g)
    , b(b)
    , a(a)
    {
    }
    

    Im Weiteren ist nicht klar, wozu getColor() einen bool zurückgibt und eine Referenz als Parameter nimmt. Den Typen unsigned float gibts erst gar nicht. Alles public zu machen ist auch fragwürdig. Das /*static*/ verwirrt nur.

    Nicht böse gemeint, aber mir scheint, du solltest auch noch ein wenig Grundlagen anschauen 🙂



  • Nimm das bitte nicht persönlich, gamer8o4, aber auch abgesehen von den Präfixen ist der Code ein schlechtes Beispiel.

    Nein nein, ich bin selber noch ein halber anfänger 😃
    Aber hab trotzdem nochmal ein paar fragen zu deinen anmerkungen....

    du die Konstruktor-Initialisierungsliste verwenden
    

    so wie es ist kann man aber ganz einfach die getColor() funktion umschreiben um z.b. alle farben im farbkasten dunkler zu machen. das kann man nicht im konstruktor machen , weil man sonst die CColor objekte nicht mehr so gut zwischen verschiedenen farbkästen hin-und-her reichen könnte.

    Und ein color-Typedef für eine Farbkomponente (nicht Farbe) ist fragwürdig.

    okay, das ist echt dämlich 🤡

    Ebenso, wieso du einmal float und einmal unsigned char verwendest

    ich hab mir angewöhnt die sichtbarkeit als float zu speichern, weil sie dann genauer angeben kann und nicht mit werten zwischen 0 und 255 rumhantieren muss.

    und ebenso die Defaultparameter (bis auf den letzten).

    was gibt es an standartwerten auszusetzen? die hab nur genommen, damit ich keinen standartkonstruktor schreiben muss, der eine standartfarbe setzt.

    wozu getColor() einen bool zurückgibt

    sorry, hab ich vergessen zu ändern, die funktion sah erst anders aus 😕

    zurückgibt und eine Referenz als Parameter nimmt

    warum soll man erst ein neues object von CColor erstellen, wenn man auch einfach ein vorhandenes nehmen kann? anders sehe der code so aus und das ist ineffizienter:

    CColor c = getColor(100,10,75,1.0f);
    

    Alles public zu machen ist auch fragwürdig.

    was willst du denn da private machen?

    Nicht böse gemeint, aber mir scheint, du solltest auch noch ein wenig Grundlagen anschauen

    bin immernoch halb dabei, auch wenn ich seit 2,5 jahren c++ programmiere 😕
    aber wie ich immer sage, mit 16 hab ich noch genug zeit das zu lernen 🙂



  • Ich würde hier auch sicher keine verschachtelten Klassen verwenden.

    Im Grunde stell ich mir die Struktur in etwa so vor. Du hast deine Grafikobjekte, die von einer Basisklasse erben, z.B. DrawingItem mit den Ableitungen DrawingItemRect, DrawingItemCircle usw. Die haben Eigenschaften wie Koordinaten, Farbe usw. Dann gibt es entsprechende Factories, das sind die Tools, die man in der Toolbox auswählen kann. z.B. ein RectDrawingTool oder wie auch immer. Die Toolbox kann sie instanziieren und verwalten. Die brauchen widerum aber keinen Zugriff auf die Toolbox. Hier bin ich mir jetzt nicht sicher, weil ich nicht alle Anforderungen kenne und das ganze entsprechend nicht durchdacht ist. Aber die brauchen Zugriff auf die aktuellen Einstellungen. Ich würde es als Objekt unabhängig von der Toolbox modellieren. Vielleicht eine Klasse DrawingSettings, die auch Einstellugnen wie Farbe, Pinseldicke usw. hat. Die Tools bekommen eine Instanz übergeben. Die Toolbox verwaltet diese Instanz und kann die Eigenschaft ändern. Wenn du das Tool das nächste mal zum Zeichnen verwendest, hat es automatisch die aktuellen Einstellungen, die über die Toolbox gesetzt wurden.



  • Im Grunde stell ich mir die Struktur in etwa so vor. Du hast deine Grafikobjekte, die von einer Basisklasse erben, z.B. DrawingItem mit den Ableitungen DrawingItemRect, DrawingItemCircle usw. Die haben Eigenschaften wie Koordinaten, Farbe usw. Dann gibt es entsprechende Factories, das sind die Tools, die man in der Toolbox auswählen kann. z.B. ein RectDrawingTool oder wie auch immer. Die Toolbox kann sie instanziieren und verwalten. Die brauchen widerum aber keinen Zugriff auf die Toolbox. Hier bin ich mir jetzt nicht sicher, weil ich nicht alle Anforderungen kenne und das ganze entsprechend nicht durchdacht ist. Aber die brauchen Zugriff auf die aktuellen Einstellungen. Ich würde es als Objekt unabhängig von der Toolbox modellieren. Vielleicht eine Klasse DrawingSettings, die auch Einstellugnen wie Farbe, Pinseldicke usw. hat. Die Tools bekommen eine Instanz übergeben. Die Toolbox verwaltet diese Instanz und kann die Eigenschaft ändern. Wenn du das Tool das nächste mal zum Zeichnen verwendest, hat es automatisch die aktuellen Einstellungen, die über die Toolbox gesetzt wurden.

    das ist schlau 🤡 aber ich glaube das wird an dieser stelle etwas kompliziert dann für den anfang oder?

    für ein einfaches Zeichenprogramm



  • Hallo zusammen!

    Ich versuchte mein Problem anhand eines ganz simplen Beispiels zu erklären, was aber vermutlich mißlungen ist.

    Konkret arbeite ich an einem MFC-Windowsprogramm mit GDI+ Grafik, das eine lange Reihe von Grafikresourcen bereitstellen muss:

    Sehr verkürzte Darstellung! :

    Pen *pen1;
    Pen *pen2;
    Pen *pen3;
    Pen *pen4;

    SolidBrush *solidBrushSchwarz;
    SolidBrush *solidBrushWeiss;
    SolidBrush *solidBrushGrau;
    SolidBrush *solidBrushHellgrau;

    Gdiplus::Font *fontSymbol;
    Gdiplus::Font *fontSymbolText;
    usw...

    Weil es sich um eine sehr lange Liste von Grafikresourcen handelt, möchte ich von ihnen zur Laufzeit nur 1 Instanz erzeugen.

    An anderer Stelle im Programm habe ich dann viele Funktionen, die auf die obengenannten GDI+ Resourcen Zugriff haben müssen und zwar in der Regel auf fast alle gleichzeitig.

    Wie wird der einfache Zugriff einer solchen Sammlung von Grafikresourcen nun am elegantesten in so ein Programm implementiert?



  • Wie wird der einfache Zugriff von Grafikresourcen nun am elegantesten in so ein Programm implementiert?

    schreib dir einen kleinen GrafikManager der einen vector mit den grafikresourcen verwaltet (mit verwalten ist hier folgendes gemeint: zugriff ermöglichen, laden und löschen verwalten)

    Konkret arbeite ich an einem MFC-Windowsprogramm mit GDI+ Grafik

    dachte du bist anfänger? also ernstgemeinter tipp, wenn du wirklich noch ein anfänger bist, dann lass die finger von der MFC, da wäre nämlich ein wissen über generelle application designs insbesondere dem Doc-View-Design echt mehr als sinnvoll.. (hab selber böse erfahrungen gemacht, ich bin nämlich mit spieleprogrammierung eingestiegen ^^)



  • mireiner schrieb:

    Wie wird der einfache Zugriff von Grafikresourcen nun am elegantesten in so ein Programm implementiert?

    Jede Zeichenfunktion OnDraw eines Dialogs darf den Zeichenklasten kennen. Pro Dialog ein Zeiger auf den Zeichenkasten ist wohl ok. Und die aufgerufenen Funktioinen bekommen den Zeiger auf den Zeichenkasten halt mit.



  • Hallo volkard,

    ah, mit einem Zeiger! Das ist glaube ich die Lösung auf die ich nicht gekommen bin.

    Damit werde ich es erst einmal versuchen.

    Danke und Grüße auch an alle anderen für ihre Ratschläge!
    Bernd



  • gamer8o4 schrieb:

    so wie es ist kann man aber ganz einfach die getColor() funktion umschreiben um z.b. alle farben im farbkasten dunkler zu machen. das kann man nicht im konstruktor machen , weil man sonst die CColor objekte nicht mehr so gut zwischen verschiedenen farbkästen hin-und-her reichen könnte.

    Was hat das mit der Konstruktor-Initialisierungsliste zu tun?

    Die getColor() -Funktion ist komplett überflüssig, da man statt getColor(c, r, g, b, a) immer auch c = Color(r, g, b, a) schreiben kann, was auch weniger verwirrend ist ("get" wird für anderes eingesetzt)...

    gamer8o4 schrieb:

    ich hab mir angewöhnt die sichtbarkeit als float zu speichern, weil sie dann genauer angeben kann und nicht mit werten zwischen 0 und 255 rumhantieren muss.

    Und für RGB gilt das nicht? Davon abgesehen wird die Grafikschnittstelle wahrscheinlich eh nur 256 verschiedene Alpha-Werte akzeptieren...

    gamer8o4 schrieb:

    was gibt es an standartwerten auszusetzen? die hab nur genommen, damit ich keinen standartkonstruktor schreiben muss, der eine standartfarbe setzt.

    Dass man den Konstruktor mit 1 oder 2 Argumenten aufrufen kann, was nicht sinnvoll ist.

    Color c(35, 100); // welche Komponenten sind nun gesetzt?!
    Color c = 200; // wtf!? auch möglich, da nicht explicit
    

    gamer8o4 schrieb:

    warum soll man erst ein neues object von CColor erstellen, wenn man auch einfach ein vorhandenes nehmen kann? anders sehe der code so aus und das ist ineffizienter:

    Es spielt genau gar keine Rolle, ob du das ganze Objekt oder dessen Member einzeln zuweist. Abgesehen davon sollte der Code zuerst einen vernünftigen Stil befolgen, bevor du an solche Mikrooptimierungen überhaupt denkst. Selbst wenn du hier 2 Nanosekunden herausholen solltest (was du nicht tust), wäre das komplett irrelevant, weil du andernorts viel mehr verbrätst. Was du hingegen nicht berücksichtigst, ist die Referenz und deren Dereferenzierung, was ohne Optimierung auch nicht gratis ist.

    Fazit: Code erst schön schreiben. Nur schnell, wenn nötig.

    gamer8o4 schrieb:

    was willst du denn da private machen?

    Ich würde gar keine Klasse machen, die nur andere enthält. Allenfalls ein Namensraum, aber hier kommt man gut ohne aus.

    gamer8o4 schrieb:

    aber wie ich immer sage, mit 16 hab ich noch genug zeit das zu lernen 🙂

    Schau dir vielleicht auch ein gutes Buch wie den C++ Primer (nicht Primer Plus) an. Nur durch Programmieren lernt man -- gerade in C++ -- vieles nicht.



  • Mir ist gerade noch eine Idee gekommen, weiß aber nicht, ob sie möglich ist?

    Eine Basisklasse mit einem Element "Baukasten", von dem zur Laufzeit nur 1 Instanz erzeugt wird und alle von dieser Basisklasse abgeleiteten Klassen können auf einfachem Wege auf diesen EINEN Baukasten der Basisklasse zugreifen.

    Gibt es in C++ Sprachelemente die so etwas möglich machen?

    Funktioniert das womöglich, wenn das Element "Baukasten" in der Basisklasse als statisch deklariert wird?



  • Ja, static ermöglicht sowas. Führst du das weiter, kommst du zum Singleton-Pattern. Hier gabs gerade ne Diskussion darüber, warum das üblicherweise verpönt ist 😉



  • gamer8o4 schrieb:

    zurückgibt und eine Referenz als Parameter nimmt

    warum soll man erst ein neues object von CColor erstellen, wenn man auch einfach ein vorhandenes nehmen kann? anders sehe der code so aus und das ist ineffizienter:

    CColor c = getColor(100,10,75,1.0f);
    

    Oh aha. Also gibt es in deiner Welt kein inlining und RVO? Hast du gebnchmarkt? compilierst du mit simpelsten optimierungen? Machen das coole Kids heute so?



  • mireiner schrieb:

    Eine Basisklasse mit einem Element "Baukasten", von dem zur Laufzeit nur 1 Instanz erzeugt wird und alle von dieser Basisklasse abgeleiteten Klassen können auf einfachem Wege auf diesen EINEN Baukasten der Basisklasse zugreifen.

    Gibt es in C++ Sprachelemente die so etwas möglich machen?

    Funktioniert das womöglich, wenn das Element "Baukasten" in der Basisklasse als statisch deklariert wird?

    klingt nach globalen variablen (sehr schlechter stil) oder Singletons (wurde mir heute gesagt, dass man die auch nicht zu oft verwenden sollte) 😃
    mit static würde theoretisch auch funktionieren, aber naja, das könnte man in diesem fall als schlechte singleton implementierung oder auch als komische globale variable bezeichnen 😕



  • otze schrieb:

    gamer8o4 schrieb:

    zurückgibt und eine Referenz als Parameter nimmt

    warum soll man erst ein neues object von CColor erstellen, wenn man auch einfach ein vorhandenes nehmen kann? anders sehe der code so aus und das ist ineffizienter:

    CColor c = getColor(100,10,75,1.0f);
    

    Oh aha. Also gibt es in deiner Welt kein inlining und RVO? Hast du gebnchmarkt? compilierst du mit simpelsten optimierungen? Machen das coole Kids heute so?

    okay ich gebe auf 🤡



  • [quote="mireiner"]Mir ist gerade noch eine Idee gekommen, weiß aber nicht, ob sie möglich ist?

    Es ist möglich.

    [quote="mireiner"]Eine Basisklasse mit einem Element "Baukasten", von dem zur Laufzeit nur 1 Instanz erzeugt wird und alle von dieser Basisklasse abgeleiteten Klassen können auf einfachem Wege auf diesen EINEN Baukasten der Basisklasse zugreifen.

    ALso eine globakle Variable Baukasten.

    mireiner schrieb:

    Gibt es in C++ Sprachelemente die so etwas möglich machen?

    Ja, tausende.
    Am einfachsten, Du machst eine globale Variable, wenn Du eine meinst.

    mireiner schrieb:

    Funktioniert das womöglich, wenn das Element "Baukasten" in der Basisklasse als statisch deklariert wird?

    Klar. Aber warum dafür Vererbung anstrengen? Vererbung ist doch der echt nichtnaheliegende Weg, eine globale Variable zu deklarieren.



  • Hallo Nexus!

    War nur so eine Idee von mir. Wenn das wirklich möglich ist, hört sich das in meinen Ohren erst mal als die ultimative Lösung für mein Problem an.

    Das werde ich dann gleich einmal anhand eines einfachen Praxisbeispiels ausprobieren. Danke auch für den Hinweis auf den Singeton Pattern Thread, davon habe entfernt schon einmal etwas gehört.

    Grüße,
    Bernd



  • @volkard

    Klar. Aber warum dafür Vererbung anstrengen? Vererbung ist doch der echt nichtnaheliegende Weg, eine globale Variable zu deklarieren.

    Mmh, ich dachte ein statisches Element einer Basisklasse wäre vielleicht besser gekapselt als ein globales Objekt. Da es sich ja um sehr viele (statische) Grafikresource-Elemente handelt, wäre der Zugriff, für die von dieser Basisklasse abgeleiteten Klassen, auch denkbar einfach...



  • mireiner schrieb:

    die ultimative Lösung für mein Problem

    Davon habe ich vielleicht eine im Jahr.
    Sonst immer habe ich etliche sehr gute Lösungen und muss abwägen, welche wohl vermutlich mich langfristig nicht umbringt. Wer abschätzen kann, was einen nicht innerhalb eines Tages umbringt, ist ein Programmierer; wer abschätzen kann, was einen nicht in einer Woche umbringt, ist ein Entwickler; wer 3 Monate schafft, ist ein Software-Architekt; und wer ein Jahr schafft, ist ein Angeber.


Anmelden zum Antworten