Basisklasse erstellen?
-
Klar macht es Sinn, eine Basisklasse für beide zu erstellen, denn ein Großteil der Funktionen und Membervariablen sind ja komplett identisch.
Packe einfach die entsprechenden Member in die neue Basisklasse und lasse dann beide bisherigen Klassen davon erben.
Bei Unterschieden gibt es zwei Möglichkeiten:
1. du machst die Basisklassenfunktion abstrakt und implementierst dann jeweils in den beiden Unterklassen die unterschiedliche Funktionalität
oder
2. du gibst in der Basisklasse eine der beiden Funktionalitäten als Vorgabe (virtual) und implementierst nur die andere Funktionalität in der anderen Unterklasse.So brauchst du auch nur noch eine Funktion
void Dot( Console& console, const Base& base, // <-- hier natürlich einen besseren Namen finden int dotX1, int dotY1, std::string ch_name, std::size_t ch_idx, const bool& show );
Andererseits sehe ich bisher am Source-Code zwischen beiden Klassen (und auch zwischen beiden Namen!) nicht, warum du überhaupt zwei verschiedene Funktionalitäten benötigst???
Bis auf die Faktoren in get_Dims und resizeCoords sowie der Vector 'unicodes' sind sie identisch, und die könnte man auch einfach durch passende Eigenschaften (Konstruktorparameter bzw. Setter) bereitstellen.
-
Gut, danke für die Zielrichtung.
Th69 schrieb:
Andererseits sehe ich bisher am Source-Code zwischen beiden Klassen (und auch zwischen beiden Namen!) nicht, warum du überhaupt zwei verschiedene Funktionalitäten benötigst???
Bis auf die Faktoren in get_Dims und resizeCoords sowie der Vector 'unicodes' sind sie identisch, und die könnte man auch einfach durch passende Eigenschaften (Konstruktorparameter bzw. Setter) bereitstellen.Ja, ich glaube ich verstehe, wie Du das meinst. Musste tatsächlich erst beide Klassen ausschreiben, bevor ich die Gemeinsamkeiten bzw Unterschiede so deutlich erkannt hatte.
-
PS: Hat jemand ne Vorstellung, wie ein Oberbegriff von draw und paint aussehen könnte? Arts...?
-
Hallo,
wenn ich jetzt eine KLasse zB
Tools
habe, ist dann der Ansatz möglich und richtig, zwei Objekte zBpaint
unddraw
zu erstellen, die ihre eigenen Werte haben?Tools draw ( console ); Tools paint ( console );
-
Ja, so funktioniert objektorientierte Programmierung
Ich verstehe nur nicht warum du die Klasse jetzt Tools nennst, und dich zwischen Draw oder Paint entschieden hast. Tools kann ja ziemlich alles sein.
-
Jupp, danke, bin ich auf der richtigen Fährte
Nun ja, da sowohl
draw
undpaint
Werkzeuge sind, um mein Ziel zu erreichen, dachte ich, ist doch ein guter Name.Bin Kritiken gegenüber aber aufgeschlossen, wenn es ne Alternative gibt, ok. (*)
(*) Als Beispiel möchte ich nennen, das mir jemand beim Verändern der Konsole den Tip gab, Funktionen mit
resize()
undmove()
) zu benennen. Dadurch wurde der weitere Code enorm erleichtert!
-
Über Benennungen kann man sich vorzüglich streiten, ich würde aber empfehlen Klassennamen so zu wählen, dass daraus, im entsprechenden Kontext, eindeutig ersichtlich wird, was die Klasse macht. Und da finde ich "Tools" ziemlich nichtssagend. In deinem Fall vlt. sowas wie "ConsolePainter".
Edit: Tools wäre meiner Meinung nach evt. ein gutes Basisklassennamen für verschiedene Werkzeuge um z.B. die Konsole zu manipulieren.
-
Allerdings kann man sich das auch in einem fertigen Programm vorstellen. Es gibt eine Klasse Tools, um Aufgaben zu bewältigen. Bei Bedarf kann man dann noch ein Objekt spray, fill etc einfügen.
Ist aber nur ein temporärer Name, bis sich der Kontext wieder ändert.
Nene,
class Comnsole
ist ne eigene Klasse, die einfach da ist. Da gibt es außer Werte holen edit: und moving und so, von anderen nichts mehr zu machen. Außer der Parameter soll nichts auf die Grundlage console hinweisen.Hoffe ich jedenfalls
-
Verdammt, über Klassennamen nachzudenken ist ja schon fast psychologische Grundlagenforschung
-
Ich komm hier nicht weiter. Mein erster Versuch ist etwas lächerlich, weil ich keine Ahnung habe, habe ich dies so zusammengeschustert.
Ich kann zwar zwei Objekte erstellen, aber schon verschiedene Chars für diese muss ich so hausbacken einlesen.#pragma once #include "console.h" #include <map> class immernochKeinPlanfürName { public: const Console& console; std::map <std::string, std::vector <CHAR_INFO>> ch_draw, ch_paint; Tools( Console& console ) : console ( console ) { getDefaultCoords(); getDefaultChars(); } unsigned int getXWidth() const { return used.width; } unsigned int getYHeight() const { return used.height; } int getCenterX() const { return used.center_x; } int getCenterY() const { return used.center_y; } unsigned int getDimXWidth() const { return dim.width; } unsigned int getDimYHeight() const { return dim.height; } int getDimCenterX() const { return dim.center_x; } int getDimCenterY() const { return dim.center_y; } unsigned int getCoordXWidth() const { return coord.width; } unsigned int getCoordYHeight() const { return coord.height; } int getCoordCenterX() const { return coord.center_x; } int getCoordCenterY() const { return coord.center_y; } void resizeCoords( unsigned int, unsigned int ); void resetCoords(); void resizeCenter( int, int ); void resizeCenterToConsole(); void resetCenter(); void addDrawChars( std::string, const std::vector <WCHAR>&, const std::vector <WORD>& ); void addPaintChars( std::string, const std::vector <WCHAR>&, const std::vector <WORD>& ); private: struct Coord { unsigned int width = 0; unsigned int height = 0; int center_x = 0; int center_y = 0; bool b = false; }; Coord dim, coord, used; std::string draw_default_name = "default"; std::vector <WCHAR> draw_uni = { '*', '@', 219 }; std::vector <WORD> draw_attr = { 0, 15, 7, 8, 4, 12, 6, 14, 10, 11, 3, 9, 1, 13, 5 }; std::string paint_default_name = "default"; std::vector <WCHAR> paint_uni = { 179, 176, 178, 219 }; std::vector <WORD> paint_attr = { 0, 15, 7, 8, 4, 12, 6, 14, 10, 11, 3, 9, 1, 13, 5 }; void getDefaultCoords() { getConsoleCoords(); }; void getDefaultChars() { addDrawChars( draw_default_name, draw_uni, draw_attr ); addPaintChars( paint_default_name, paint_uni, paint_attr ); }; void getConsoleCoords(); unsigned int toUInt( double ); int toInt( double ); }; ////////////////////////////////////////////////////////////////////////////////////////
Da ich keine Idee habe, wo ich was nachschlagen muss, habe ich mal bei Vererbung geschaut.
#pragma once #include "console.h" class Tools { public: const Console& console; Tools( Console& console ) : console ( console ) { getDefaultCoords(); } unsigned int getXWidth() const { return used.width; } unsigned int getYHeight() const { return used.height; } int getCenterX() const { return used.center_x; } int getCenterY() const { return used.center_y; } unsigned int getDimXWidth() const { return dim.width; } unsigned int getDimYHeight() const { return dim.height; } int getDimCenterX() const { return dim.center_x; } int getDimCenterY() const { return dim.center_y; } unsigned int getCoordXWidth() const { return coord.width; } unsigned int getCoordYHeight() const { return coord.height; } int getCoordCenterX() const { return coord.center_x; } int getCoordCenterY() const { return coord.center_y; } void resizeCoords( unsigned int, unsigned int ); void resetCoords(); void resizeCenter( int, int ); void resizeCenterToConsole(); void resetCenter(); private: struct Coord { unsigned int width = 0; unsigned int height = 0; int center_x = 0; int center_y = 0; bool b = false; }; Coord dim, coord, used; void getDefaultCoords() { getConsoleCoords(); }; void getConsoleCoords(); unsigned int toUInt( double ); int toInt( double ); }; ////////////////////////////////////////////////////////////////////////////////////////
#pragma once #include "tools.h" #include <map> class Draw : public Tools { public: //const Console& console; std::map <std::string, std::vector <CHAR_INFO>> ch_draw, ch_paint; Draw() { getDefaultChars(); } void addDrawChars( std::string, const std::vector <WCHAR>&, const std::vector <WORD>& ); void addPaintChars( std::string, const std::vector <WCHAR>&, const std::vector <WORD>& ); private: std::string draw_default_name = "default"; std::vector <WCHAR> draw_uni = { '*', '@', 219 }; std::vector <WORD> draw_attr = { 0, 15, 7, 8, 4, 12, 6, 14, 10, 11, 3, 9, 1, 13, 5 }; std::string paint_default_name = "default"; std::vector <WCHAR> paint_uni = { 179, 176, 178, 219 }; std::vector <WORD> paint_attr = { 0, 15, 7, 8, 4, 12, 6, 14, 10, 11, 3, 9, 1, 13, 5 }; void getDefaultChars() { addDrawChars( draw_default_name, draw_uni, draw_attr ); addPaintChars( paint_default_name, paint_uni, paint_attr ); }; }; ////////////////////////////////////////////////////////////////////////////////////////
Dort wird in Zeile 6 angemängelt
draw.h|6|error: expected unqualified-id before 'class'| draw.h|6|error: expected constructor, destructor, or type conversion before 'class'| ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|
Ich weiß nicht, was dort erwartet wird.
-
Hm, ein paar Dinge, ohne zu überprüfen ob das deine Fehlermeldung löst.
In
class immernochKeinPlanfürName hast du folgendes:Tools( Console& console ) : console ( console ) { getDefaultCoords(); getDefaultChars(); }
Wahrscheinlich soll das heißen:
immernochKeinPlanfürName ( Console& console ) : console ( console ) { getDefaultCoords(); getDefaultChars(); }
In Tools hast du einen Konstruktor definiert. Du verstößt aber gegen die Rule of 5.
Das führt auch zu einem Problem in Draw. Aus dem Draw Konstruktor wird der Basisklassen Konstruktor aufgerufen. Nur welchen soll er nehmen. Du hast einen eigenen definiert, daher wird kein default Konstruktor erstellt. Und den erstellten Kontsruktor kann er nicht aufrufen, weil der ein Parameter erwartet.Außerdem solltest du bei polymorphen Klassen, einen virtuellen Destruktor definieren. Je nach Nutzung kann das sonst später zu undefiniertem Verhalten führen.
-
schlangenmensch schrieb:
In Tools hast du einen Konstruktor definiert. Du verstößt aber gegen die Rule of 5.
Was willst du damit sagen? Meinst du man kann keinen eigenen Konstruktor definieren, ohne die anderen Operatoren und Methoden der Rule of 5 zu definieren.
Die Rule of 3 (bzw. 5) bezieht sich nur auf den Kopierkonstruktor.
-
Argh... wo zum Teufel habe ich nur mein Kopf. Sicher, erfolgreiche Umsetzung der Rule of 0....
Wodrauf ich eigentlich hinaus wollte ist, dass der Default Konstrukor nicht automatisch erzeugt wird, wenn er einen eigenen Konstruktor definiert.
Und der würde hier aber für Draw::Draw() benötigt.
-
Ja, da gebe ich dir recht. Trotzdem wird hier keine Ableitung benötigt: eine Klasse (wie auch immer diese heißen mag) sowie zwei Instanzen 'Draw' und 'Paint' davon (bzw. 2 Funktionen, welche diese Instanzen erzeugen).
Wobei ich immer noch nicht den Unterschied zwischen den beiden Namen verstanden habe. Warum braucht man zwei verschiedene "Dinge", um etwas auf der Konsole auszugeben/auszudrucken/zu zeichnen???
-
Der Klassenanme "immernoch kein Plan" steht natürlich nur hier, nicht im Code.
Th69 schrieb:
Wobei ich immer noch nicht den Unterschied zwischen den beiden Namen verstanden habe. Warum braucht man zwei verschiedene "Dinge", um etwas auf der Konsole auszugeben/auszudrucken/zu zeichnen???
Dies ist meines Erachten leicht aufzuklären. In der Konsole sind die Zeichen ziemlich genau x * 2y groß. Dies muss berücksichtigt werden, wenn zB ein 50 x 50 Quadrat in der Konsole auch ein Quadrat sein soll. Beim 'zeichnen' muss man außer darauf nicht weiter achten. Beim 'malen' aber, damit die "Pixel" selbst auch quadratisch sind, jeden einzelne zweimal 'zeichnen'.
Dazu soll sowohl 'zeichnen' und 'malen' eigene Skalierungsoptionen bekommen. Beispiel: Man hat einen Hintergrund, irgendein Muster 'gemalt', darüber wird ein anderes Muster 'gezeichnet'. Wenn ich letzteres jetzt einfach animieren (verschieben, vergrößern, skalieren, etc) will, würde auch das 'gemalte' Muster entsprechend animiert werden. Das will ich natürlich nicht.
Ein kleines Beispiel:
https://www.youtube.com/watch?v=BKNUR2wNsoA
Dort wurden die Werte der Formen nicht verändert, nur die Skalierung vondraw
void Demo( Console& console, Tools& draw, Tools& paint, unsigned int console_size ) { console.setTitle( "" ); console.resize( console_size ); draw.resetCoords(); paint.resetCoords(); paintModularColors( console, paint ); unsigned int scale_size_min = 10; unsigned int scale_size_max = 75; draw.resizeCoords( scale_size_min, scale_size_min ); int loops = 10, l = 0; while ( l < loops ) { for ( unsigned int zs = scale_size_min; zs <= scale_size_max; zs += 5 ) { Sleep( 10 ); draw.resizeCoords( zs, zs ); paintModularColors( console, paint ); drawForms( console, draw, "default", 16 ); console.writeBuffer(); } for ( unsigned int zs = scale_size_max; zs >= scale_size_min; zs -= 5 ) { Sleep ( 10 ); draw.resizeCoords( zs, zs ); paintModularColors( console, paint ); drawForms( console, draw, "default", 16 ); console.writeBuffer(); } l ++; } std::cin.get(); console.clearBuffer(); }
Hoffe, ich hatte Dich bei der Aufklärung richtig verstanden.
-
Schlangenmensch schrieb:
Wodrauf ich eigentlich hinaus wollte ist, dass der Default Konstrukor nicht automatisch erzeugt wird, wenn er einen eigenen Konstruktor definiert.
Und der würde hier aber für Draw::Draw() benötigt.
Ja, das meine ich verstanden zu haben, darauf zielt ja auch die Fehlermeldung, das dort noch etwas in der Richtung erwartet wird. Ich weiß aber nicht, wie ich das ausschreiben muss.
-
Naja, deine Basisklasse braucht offensichtlich eine Console. Die wirst du irgendwie übergeben müssen. Zum Beispiel könnte dien Konstruktor so aussehen:
Draw(Console& console):Tools(console) { getDefaultChars(); }
-
Danke, es wird aber immer noch
class Draw : public Tools
mit
draw.h|6|error: expected unqualified-id before 'class'| draw.h|6|error: expected constructor, destructor, or type conversion before 'class'| ||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 1 second(s)) ===|
bemängelt. Gucke auch immer x-mal, ob die Werte in
class Draw
wirklich public inclass Tools
sind(*). Was könnte denn vorclass
erwartet werden?(*)Obwohl das Quatsch ist, in Draw sind ja nur die Chars und in Tools nur die Coords.
-
Nur noch mal zur Erinnerung, diese Klasse funktioniert wie gewünscht und damit ist auch die kleine Demo entstanden. Allerdings finde ich es nicht schön, das ich zwar zwei Objekte
draw
undpaint
erstellen kann, in beiden aber jeweils die Chars für draw und paint enthalten sind.#pragma once #include "console.h" #include <map> class Tools { public: const Console& console; std::map <std::string, std::vector <CHAR_INFO>> ch_draw, ch_paint; Tools( Console& console ) : console ( console ) { getDefaultCoords(); getDefaultChars(); } unsigned int getXWidth() const { return used.width; } unsigned int getYHeight() const { return used.height; } int getCenterX() const { return used.center_x; } int getCenterY() const { return used.center_y; } unsigned int getDimXWidth() const { return dim.width; } unsigned int getDimYHeight() const { return dim.height; } int getDimCenterX() const { return dim.center_x; } int getDimCenterY() const { return dim.center_y; } unsigned int getCoordXWidth() const { return coord.width; } unsigned int getCoordYHeight() const { return coord.height; } int getCoordCenterX() const { return coord.center_x; } int getCoordCenterY() const { return coord.center_y; } void resizeCoords( unsigned int, unsigned int ); void resetCoords(); void resizeCenter( int, int ); void resizeCenterToConsole(); void resetCenter(); void addDrawChars( std::string, const std::vector <WCHAR>&, const std::vector <WORD>& ); void addPaintChars( std::string, const std::vector <WCHAR>&, const std::vector <WORD>& ); private: struct Coord { unsigned int width = 0; unsigned int height = 0; int center_x = 0; int center_y = 0; bool b = false; }; Coord dim, coord, used; std::string draw_default_name = "default"; std::vector <WCHAR> draw_uni = { '*', '@', 219 }; std::vector <WORD> draw_attr = { 0, 15, 7, 8, 4, 12, 6, 14, 10, 11, 3, 9, 1, 13, 5 }; std::string paint_default_name = "default"; std::vector <WCHAR> paint_uni = { 179, 176, 178, 219 }; std::vector <WORD> paint_attr = { 0, 15, 7, 8, 4, 12, 6, 14, 10, 11, 3, 9, 1, 13, 5 }; void getDefaultCoords() { getConsoleCoords(); }; void getDefaultChars() { addDrawChars( draw_default_name, draw_uni, draw_attr ); addPaintChars( paint_default_name, paint_uni, paint_attr ); }; void getConsoleCoords(); unsigned int toUInt( double ); int toInt( double ); }; //////////////////////////////////////////////////////////////////////////////////////// inline void Tools::getConsoleCoords() { dim.width = console.getRows(); //um selbe x- und y-Weiten zu haben dim.height = console.getRows(); dim.center_x = toInt( dim.width / 2.0 ); dim.center_y = toInt( dim.height / 2.0 ); dim.b = true; coord = dim; used = dim; } inline void Tools::resizeCoords( unsigned int co_width, unsigned int co_height ) { coord.width = co_width; coord.height = co_height; used = coord; } inline void Tools::resetCoords() { getConsoleCoords(); } inline void Tools::resizeCenter( int x, int y ) { used.center_x = x; used.center_y = y; } inline void Tools::resizeCenterToConsole() { resizeCenter( toInt( console.getCenterX() / 2.0 ), console.getCenterY() ); } inline void Tools::resetCenter() { used.center_x = dim.center_x; used.center_y = dim.center_y; } inline void Tools::addDrawChars( std::string draw_name, const std::vector <WCHAR>& draw_uni, const std::vector <WORD>& draw_attr ) { CHAR_INFO ch; std::vector <CHAR_INFO> tmp_vec; for ( auto i : draw_uni ) { for ( auto j : draw_attr ) { ch.Char.UnicodeChar = i; ch.Attributes = j; tmp_vec.push_back( ch ); } } ch_draw.insert( std::make_pair( draw_name, tmp_vec )); } inline void Tools::addPaintChars( std::string paint_name, const std::vector <WCHAR>& paint_uni, const std::vector <WORD>& paint_attr ) { CHAR_INFO ch; std::vector <CHAR_INFO> tmp_vec; for ( auto i : paint_uni ) { for ( auto j : paint_attr ) { ch.Char.UnicodeChar = i; ch.Attributes = j; tmp_vec.push_back( ch ); } } ch_paint.insert( std::make_pair( paint_name, tmp_vec )); } inline unsigned int Tools::toUInt( double val ) { return static_cast<unsigned int> ( std::round( val ) ); } inline int Tools::toInt( double val ) { return static_cast<int> ( std::round( val ) ); }
int main() { Console console; Tools draw( console ); Tools paint( console ); }
-
Da dein Code nicht vollständig ist, kann ich das nicht sagen. Du wirst irgendwo einen Syntax Fehler haben.
Ich habe mal hier: http://cpp.sh/3t7l
Includes hinzugefügt und die Variablen Typen so gewählt, dass der Spaß ohne größere weitere Includes funktioniert und kompiliert.Edit: Wenn du nur unterschiedliche Chars zeichnen willst, kannst du doch deinem Konstruktor einfach ein Vekor mit den zu zeichnenden chars mitgeben...