Basisklasse erstellen?



  • Wow, danke 🙂

    Wollte erstmal nur ne kurze Rückmeldung geben, weil ich während einer gefühlten Achterbahnfahrt suchen musste, warum Dein Code kein Fehler meldet, dafür aber meiner.

    An der Schreibweise, alle Klassen und dadurch auch alle includes in ein code zu geben, wirds ja wohl nicht gelegen haben? Muss ich aber noch verifizieren. Getestet habe ich nämlich noch nicht. Fand das nur klasse, das da jemand den Fehler korrigiert hat, ohne groß was umzuschreiben 🙂

    Ich glaube eher, bei mir war es eine Kombination aus includes, Klasse selbst und Aufrufe in der main.

    Schlangenmensch schrieb:

    Edit: Wenn du nur unterschiedliche Chars zeichnen willst, kannst du doch deinem Konstruktor einfach ein Vekor mit den zu zeichnenden chars mitgeben...

    Genau. Da ich ja jetzt nicht nur eine Unterklasse Draw , sondern auch eine Unterklasse Paint erstellen müssen könnte, gibt es natürlich für jede auch ihre eigenen vectors. Oder ich habs jetzt falsch verstanden?

    PS: Das sind doch jetzt eine Oberklasse und eine bzw zwei Unterklassen?

    EDIT: Aber schon taucht eine Frage auf. Die ganze Übung soll ja dafür sein, das ich verschiedene Objekte draw und paint habe, aber wenn ich "global" Skalierungen setzen will, ansonsten müsste ich sie immer zweimal tippen und dann hätte man sich das alles sparen können, wie mache ich das?

    int main()
    {
    
        Console console;
        Tools draw( console );
    
        console.resize ( 1200 );
        Tools::resetCoords();
    
    }
    

    geht wohl nicht?



  • Oh je, viel Asche über mein Haupt, ich krieche zu Kreutze.

    Weder habe ich den kompletten Code wie oben so übernommen (hatte ne andere .h eingebunden) noch im Detail angeschaut.

    Ich habe also immer noch den selben Fehler.
    Da ich wieder ratlos bin, wollte ich meinen Code mit dem Fehler auch mal bei C++ Shell reinstellen, aber spätestens bei

    #include<windows.h>
    

    hapert es.

    Verzeihung.

    PS: Die chars sind eine struct(?) CHAR_INFO aus der WinAPI, die haben kein char und int. Aber keine Ahnung, ob das so intern trotzdem korrekt gecastet wird. Edit#5 (ächsz): Verstehe jetzt aber, warum Du das gemacht hast 😉
    Und der Aufruf Draw d; in main() hätte nie geklappt, weil console als Parameter übergeben werden muss. Sorry.

    EDIT: Ich habe den kompletten Code (außer <windows.h>) (edit: nur die Klassen natürlich) jetzt zu nur einer header- und einer cpp-Datei (der main) komprimiert. Wenn jemand möchte, kann er sich den ja nochmal anschauen? Ich glaube, hier gibt es keine Spoilerfunktion? Sonst hätte ich ihn da schnell reingestellt.



  • Ich hatte schon befürchtet, dass win Api bei cpp.sh nicht vorhanden ist. Und ich hatte keine Lust groß includes zu suchen 😉

    Ich habe mir nochmal deine funktionierende Klasse angeschaut. Würde was gegen sowas sprechen:

    #pragma once
    
    #include "console.h"
    #include <map>
    
    class Draw
    {
    
    public:
    
        const Console& console;
        std::map <std::string, std::vector <CHAR_INFO>> ch_draw;
    
        Tools( Console& console,  const std::vector<WCHAR>& uni, const std::vector <WORD>& attr ) : console ( console ),
        draw_uni(uni),
        draw_attr(attr)
    
        {
            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>& );
    
    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;
        std::vector <WORD> draw_attr;
    
        void getDefaultCoords()
        {
            getConsoleCoords();
        };
    
        void getDefaultChars()
        {
            addDrawChars( draw_default_name, draw_uni, draw_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 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()
    {
        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::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 };
    
        Console console;
        Draw draw( console, draw_uni, draw_attr );
        Draw paint( console, paint_uni, paint_attr );
    
    }
    

    Ich habe das jetzt nicht getestet, sondern einfach deinen Code direkt hier im Forum bearbeitet. Daher sind Syntaxfehler nicht auszuschließen, außerdem ist es natürlich möglich, dass ich was übersehen habe.



  • Danke, ich will nicht unhöflich erscheinen, aber ich verstehe nicht recht, was ich mit dieser main() anfangen soll?

    Die default-Chars sind doch in den Klassen hard-gecodet, zur Not lese ich sie über eine Datei ein.

    Zur Erinnerung, die main() aus der kleinen Demo sieht so aus:

    #include "drawing_functions.h"
    #include "painting_functions.h" //hier werden die Klassen eingesetzt
    #include "demo.h" //habe ich schon gezeigt
    
    int main()
    {
    
        Console console;
        Tools draw( console );
        Tools paint( console );
    
        Demo( console, draw, paint, 1300 );
    
        ready();
    
    }
    

    Das Ding ist eben, das der Parameter console mitgegeben werden muss. Wie es in der Initialisierungsliste der Klasse steht. Es scheint aber ein Problem zu geben, dies auch einer Unterklasse mitzuteilen oder was weiß ich.

    Das Problem ist aber nicht so dringend, das irgendwas fabriziert werden muss. Am Ende der Demo interessiert es niemanden mehr, ob nun die Chars in draw und paint sauber getrennt wurden. Zählen tun nur die Skalierungsoptionen für draw und paint . Und das klappt ja.

    edit: Und bevor es großes Rätselraten um die "_functions.h" gibt, hier die drawing_functions:

    #include "drawing_functions.h"
    #include <iostream>
    #include <cmath>
    #include <sstream>
    
    void bufferDrawDot( Console& console,
                        const Tools& draw,
                        int x, int y,
                        std::string ch_name,
                        std::size_t ch_idx,
                        const bool& show )
    {
        x *= 2;
        if ( x >= 0 && x < console.getColumns() && y >= 0 && y < console.getRows() )
        {
            std::size_t out_idx = static_cast<std::size_t> ( console.getColumns() * y + x );
            console.outbuffer.at( out_idx ) = draw.ch_draw.find( ch_name )->second.at( ch_idx );
            if ( show ) console.writeBuffer(); //lässt den Weg der Dots folgen
        }
    }
    
    void bufferDrawLine( Console& console,
                         const Tools& draw,
                         int dotX1, int dotY1,
                         int dotX2, int dotY2,
                         std::string ch_name,
                         std::size_t ch_idx,
                         const bool& show )
    {
        int steps = abs( dotX2 - dotX1 );
        if (steps < abs( dotY2 - dotY1 )) steps = abs( dotY2 - dotY1);
        if (steps == 0)
        {
            std::stringstream sstr;
            sstr << "bufferDrawLine(): keine Verbindung moeglich" << '\n';
            sstr << "dotX1: " << dotX1 << "  dotX2: " << dotX2 << '\n';
            sstr << "dotY1: " << dotY1 << "  dotY2: " << dotY2 << '\n';
            //throw sstr.str();
        }
    
        double step_xwide = ( dotX2 - dotX1 ) / static_cast<double> ( steps );
        double step_ywide = ( dotY2 - dotY1 ) / static_cast<double> ( steps );
    
        double x = static_cast<double> ( dotX1 );
        double y = static_cast<double> ( dotY1 );
    
        for ( int i=0; i<steps; ++i )
        {
            bufferDrawDot( console, draw, toInt( x ), toInt( y ), ch_name, ch_idx, show );
            x += step_xwide;
            y += step_ywide;
        }
    }
    
    /////////////////////////////////////////////////////////////////////////////////////////////////////
    
    void drawDot( Console& console,
                  const Tools& draw,
                  int dotX1, int dotY1,
                  std::string ch_name,
                  std::size_t ch_idx,
                  const bool& show )
    {
        bufferDrawDot( console, draw,
                       dotX1, dotY1,
                       ch_name, ch_idx,
                       show );
    }
    
    void drawLine( Console& console,
                   const Tools& draw,
                   int dotX1, int dotY1,
                   int dotX2, int dotY2,
                   std::string ch_name,
                   std::size_t ch_idx,
                   const bool& show )
    {
        bufferDrawLine( console,
                        draw,
                        dotX1, dotY1,
                        dotX2, dotY2,
                        ch_name, ch_idx,
                        show );
    }
    
    void drawTriangle( Console& console,
                       const Tools& draw,
                       int dotX1, int dotY1,
                       int dotX2, int dotY2,
                       int dotX3, int dotY3,
                       std::string ch_name,
                       std::size_t ch_idx,
                       const bool& show )
    {
        bufferDrawLine( console, draw,
                        dotX1, dotY1, dotX2, dotY2, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        dotX2, dotY2, dotX3, dotY3, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        dotX3, dotY3, dotX1, dotY1, ch_name, ch_idx, show );
    }
    
    void drawRectangle( Console& console,
                        const Tools& draw,
                        int dotX1, int dotY1,
                        int dotX4, int dotY4,
                        std::string ch_name,
                        std::size_t ch_idx,
                        const bool& show )
    {
        bufferDrawLine( console, draw,
                        dotX1, dotY1, dotX4, dotY1, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        dotX4, dotY1, dotX4, dotY4, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        dotX4, dotY4, dotX1, dotY4, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        dotX1, dotY4, dotX1, dotY1, ch_name, ch_idx, show );
    }
    
    void drawFourSided( Console& console,
                        const Tools& draw,
                        int dotX1, int dotY1,
                        int dotX2, int dotY2,
                        int dotX3, int dotY3,
                        int dotX4, int dotY4,
                        std::string ch_name,
                        std::size_t ch_idx,
                        const bool& show )
    {
        bufferDrawLine( console, draw,
                        draw.getCenterX() + dotX1, draw.getCenterY() + dotY1,
                        draw.getCenterX() + dotX2, draw.getCenterY() + dotY2, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        draw.getCenterX() + dotX2, draw.getCenterY() + dotY2,
                        draw.getCenterX() + dotX3, draw.getCenterY() + dotY3, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        draw.getCenterX() + dotX3, draw.getCenterY() + dotY3,
                        draw.getCenterX() + dotX4, draw.getCenterY() + dotY4, ch_name, ch_idx, show );
        bufferDrawLine( console, draw,
                        draw.getCenterX() + dotX4, draw.getCenterY() + dotY4,
                        draw.getCenterX() + dotX1, draw.getCenterY() + dotY1, ch_name, ch_idx, show );
    }
    
    void drawEllipse( Console& console,
                      const Tools& draw,
                      int dotX1, int dotY1,
                      int r1, int r2,
                      std::string ch_name,
                      std::size_t ch_idx,
                      const bool& show )
    {
        int x = 0, y = 0;
        for ( auto phi=0; phi<360; ++phi )
        {
            double radian = phi * PI/180;
            x = dotX1 + toInt( r1 * cos( radian ) );
            y = dotY1 + toInt( r2 * sin( radian ) );
            bufferDrawDot( console, draw, x, y, ch_name, ch_idx, show );
        }
    }
    


  • - wegeditiert

    Sorry, aber hatte gestern einen schlechten Abend. Muss ja deswegen nicht gleich alles zeigen.



  • lemon03 schrieb:

    Danke, ich will nicht unhöflich erscheinen, aber ich verstehe nicht recht, was ich mit dieser main() anfangen soll?

    Die default-Chars sind doch in den Klassen hard-gecodet, zur Not lese ich sie über eine Datei ein.

    Ja, aber deine Hardgecodeten Vektoren sind doch der einzige Unterschied zwischen den beiden Klassen. Also habe ich als Parameter dem Konstruktor mitgegeben. Dann hast du nur eine Klasse, von der du zwei Objekte erstellen kannst. Jedem Objekt wird dann der Default Vektor übergeben. Das lässt dir auch offen, die Klasse für beliebige andere Default Vektoren wieder zu verwenden.

    Und in der main habe ich dann die Vektoren erstellt (woher die Daten dafür kommen ist mir ja egal) und den jeweiligen Objekten beim erstellen mitgegeben.

    Dein Ursprungspunkt war doch, dass du nicht unnötig zwei Vektoren mit dir rumschleppen möchtest, oder?

    Edit: Vielleicht habe ich auch dein Problem grundlegend falsch verstanden...



  • Das macht nichts, mir geht es ständig so.

    Ursprung des Anliegen war, statt ständig zB

    draw.resetCoords();
    paint.resetCoords();
    

    auszuschreiben, einen Oberbegriff, Oberklasse zu haben

    Klasse.resetCoords();
    

    Soll aber weiterhin möglich sein, auch alleine zB

    draw.resetCoords();
    

    zu schreiben. Die ganze Geschichte mit den Chars ist längst gelöst, als ich vor längeren (vor diesem Thread) zwei Klassen Draw und Paint erstellt habe, wo alles sauber getrennt ist.

    Ziel war dann aber, davon eine Oberklasse zu erstellen, die sich nur um die Coords kümmert. Wie geschrieben s.o.



  • Dann würde ich an deiner Stelle das Design der Ursprünglichen Klassen nochmal überdenken. Zwei Klassen zu haben, deren einziger Unterschied in hard-gecodeten Defaultwerten besteht ist imho nicht schön.

    Die Basisklasse gehört zu dem erstellten Objekt. Darüber lassen sich nicht alle davon abgeleiteten Klassen bzw. Objekte ändern.

    Was du aber suchst, ist nicht Vererbung, sondern Komposition.

    class Compose{
    public:
    void resetCords(){
       draw.resetCords();
       paint.resetCords
    }
    private:
       Draw draw;
       Paint paint;
    }
    

    Entsprechende Konstrukotren habe ich jetzt mal weggelassen, dient nur zur Veranschaulichung.

    Wenn du noch auf draw oder paint direkt zugreifen können möchtest, könnte man überlegen Referenzen oder Pointer zu verwenden.

    Edit: Ist ja nur noch eine Klasse. Aber da für zwei Anwendungsgebiete unterschiedliche Vektoren reingecoded zu haben ist nicht schöner 😉



  • PS: Und was ich dann zuletzt als Klasse gezeigt habe, war der Versuch, sie aufs wesentliche zu bringen, um zu zeigen, was in die Oberklasse soll und was in die Unterklassen. Und das waren dann nur die addChars(). Aber wie geschrieben s.o.



  • Aha, danke. Aber damit wir uns nicht wieder im Kreise drehen, ich hätte die verdammten Chars nie erwähnen sollen. Es geht auch darum, das die ganzen getter in Draw und Paint verschieden sein können aber nicht müssen. Wenn man dies so lösen kann, das es "globale" getter gibt und getter für Draw und Paint, dann müsste sich das mit den Chars von alleine lösen.

    Dies scheint mir aber doch komplizierter als gedacht, weshalb ich erstmal an anderer Stelle weitermache.


Anmelden zum Antworten