Methode vorher bekannt machen



  • class Bitmap;
    class Point
    {
       int x;
       int y;
       bool drawOn( Bitmap &buffer, Color &col );
    };
    class Bitmap
    {
        void doSomething();
    };
    
    bool Point::drawOn( Bitmap &buffer, Color &col )
    {
        buffer.doSomething();
    }
    


  • was ich vielleicht vergessen hab:
    Point ist eine Template-Klasse. ( Bitmap aber nicht )
    Somit kann ich ja nicht Deklaration und Implementation trennen( also *.hpp und *.cpp-Datei )

    Es ist übrigens nicht günstig, meine gesamte Problembeschreibung zu löschen, evilissimo!
    Du hättest auch normal antworten können.
    Also nochmal:

    Jetziger stand:

    struct Color
    {
        int r;
        int g;
        int b;
    };
    
    class Bitmap;
    
    template< typename PointType >
        class Point
    {
        PointType x;
        PointType y;
    
        bool drawOn( Bitmap &buffer, Color &col )
        {
            buffer.doSomething();
            //...
        }
    };
    
    class Bitmap
    {
        public:
            void doSomething( );
    };
    

    Nur wir sag ich dem Kompiler, dass Bitmap::doSomething() später noch kommt?

    MfG. Christoph Ludwig

    P.S: Alle Klassen sind in eigenen Headerdateien.



  • Jup


  • Administrator

    @ChristophLu,
    Hast du es schon probiert zu kompilieren, denn dein Code funktioniert so wie er ist. Templates werden erst genauer ausgewertet, wenn sie instanziert werden, also aus einem Klassentemplate eine Templateklasse gewonnen wird.

    Hier mal kompilierbaren Code, den du schnell durchjagen kannst, da es ein paar andere Fehler in deinem Code hat und keine main :

    struct Color 
    { 
        int r; 
        int g; 
        int b; 
    }; 
    
    class Bitmap; 
    
    template< typename PointType > 
    class Point 
    { 
        PointType x; 
        PointType y; 
    
    public:
        bool drawOn( Bitmap &buffer, Color &col ) 
        { 
            buffer.doSomething(); 
            //... 
            return true;
        } 
    }; 
    
    class Bitmap 
    { 
    public: 
        void doSomething( ) {}; 
    };
    
    int main()
    {
        Point<int> p;
        Bitmap bitmap;
        Color color;
        p.drawOn(bitmap, color);
    
        return 0;
    }
    

    Allerdings was ich hier wirklich für fragwürdig halte ist, dass Point dafür verantwortlich sein soll, um sich auf das Bitmap zu zeichnen. Halte ich für völlig verkehrt.

    Grüssli



  • Ja, ich hab es schon kompiliert. Da kommt dieser Fehler:
    invalid use of incomplete type 'Bitmap'

    Der Code oben hatte natürlich noch Fehler, weil ich ihn extrem gekürzt habe. Eigentlich ist es so:

    Headerdatei:

    class Bitmap;
    #include "Color.hpp"
    #include "Point.hpp"
    //...
    #include "Bitmap.hpp"
    

    Point.hpp:

    template< typename PointType >
        struct Point
    {
        PointType x;
        PointType y;
    
        bool drawOn( Bitmap &buffer, Color &col )
        {
            buffer.doSomething();
            //...
            return true;
        }
    };
    

    Bitmap.hpp

    class Bitmap
    {
        public:
            void doSomething( );
    };
    

    Bitmap.cpp

    #include "Bitmap.hpp"
    Bitmap::doSomething( )
    {
        //...
    }
    

    Auch wieder start abgespeckt. Nur Bitmap kann ich nicht über Point deklarieren( also #include "Bitmap.hpp" vor #include "Point.hpp" schreiben )

    Wieso verkehrt? Meinst du, ich sollte sowas in die Bitmap-Klasse schreiben, á la:

    Bitmap::drawPixel( Point<int> &position, Color &col );
    

    ?

    MfG. Christoph Ludwig


  • Administrator

    ChristophLu schrieb:

    Ja, ich hab es schon kompiliert. Da kommt dieser Fehler:
    invalid use of incomplete type 'Bitmap'

    Wegen der Fehlermeldung kurz mit GCC probiert. Ok, der kann das nicht. Dann wird es sehr wahrscheinlich der Standard auch nicht erlauben. Darüber bin ich etwas überrascht, muss ich eingestehen 😉
    Werde ich dann später noch genauer nachprüfen.

    ChristophLu schrieb:

    Auch wieder start abgespeckt.

    Ehm, hallo? Der Code ist noch abgespeckter als der vorherige. Wenn du Code präsentierst, dann ist es häufig sinnvoll etwas zu geben, dass kurz und klein ist, den Fehler aber reproduziert, dass heisst kompilierbar ist.

    ChristophLu schrieb:

    Nur Bitmap kann ich nicht über Point deklarieren( also #include "Bitmap.hpp" vor #include "Point.hpp" schreiben )

    Wieso eigentlich nicht?

    ChristophLu schrieb:

    Wieso verkehrt? Meinst du, ich sollte sowas in die Bitmap-Klasse schreiben, á la:

    Bitmap::drawPixel( Point<int> &position, Color &col );
    

    ?

    Wäre auch verkehrt. Die Aufgabe eines Punktes ist es einen Punkt zu repräsentieren, aber nicht ihn zu zeichnen. Die Aufgabe eines Bitmaps ist ein Bitmap zu repräsentieren und vielleicht Möglichkeiten anzubieten es zu verändern, aber nicht darauf zu zeichnen.

    Also muss eine Klasse her, welche für das Zeichnen zuständig ist. So machen es auch die meisten Bibliotheken. Zum Beispiel hat die WinAPI ein Graphic Device mit welchem man auf unterschiedliche Ziele Zeichnen kann, zum Beispiel auch auf einem Bitmap. Daher wäre vielleicht sowas sinnvoll:

    GraphicDevice gd(myBitmap);
    gd.drawPoint(myPoint, myColor);
    

    Grüssli



  • Oops ich seh grad das ich anstatt zu zitieren auf 'editieren' geklickt hatte. 😞
    Und den ganzen post entfernt habe. Sorry ChristophLu. 😞

    Eigentlich sollte dein editierter post eine Antwort gewesen sein 😕



  • Dravere schrieb:

    Also muss eine Klasse her, welche für das Zeichnen zuständig ist. So machen es auch die meisten Bibliotheken. Zum Beispiel hat die WinAPI ein Graphic Device mit welchem man auf unterschiedliche Ziele Zeichnen kann, zum Beispiel auch auf einem Bitmap. Daher wäre vielleicht sowas sinnvoll:

    GraphicDevice gd(myBitmap);
    gd.drawPoint(myPoint, myColor);
    

    Naja, klingt sinvoll.
    Nur will ich die Anwendung so einfach wie möglich machen. Meiner Meinung nach stört es den Lesefluss wenn man erst einen Device erstellen muss, bevor man dann endlich zeichnen kann.

    Also sowas:

    myPoint.drawOn( myBitmap, myColor );
    //ODER
    myBitmap.drawPoint( myPoint, myColor );
    

    finde ich besser als sowas in der Art:

    GraphicDevice gd( myBitmap );
    gd.drawPoint( myPoint, myColor );
    gd.release(); //(optional), aber gibts ja auch manchmal
    

    so mal nach dem KISS-Prinzip...

    MfG. Christoph Ludwig


  • Administrator

    ChristophLu schrieb:

    Nur will ich die Anwendung so einfach wie möglich machen. Meiner Meinung nach stört es den Lesefluss wenn man erst einen Device erstellen muss, bevor man dann endlich zeichnen kann.

    Ehm, aja 😕
    Also mit dem "es stört den Lesefluss" wird langsam bei allem argumentiert. Es ist eine verdammte Programmiersprache und nicht Deutsch. Man sollte hier viel mehr funktional denken.

    Zudem hinkt dein Vergleich etwas sehr. Wer schreibt dir vor, dass du das GraphicDevice immer neu erstellen musst? Und du wirst ja wohl kaum, nur um einen Punkt zu zeichnen, ein GraphicDevice erstellen. Meistens zeichnet man gleich viel mehr auf einmal. Man muss dies daher schon in der richtigen Relation sehen. Bevor man zeichnet, sagt man dem Leser ganz klar, dass man jetzt ein Objekt für das Zeichnen erstellt und dann fängt man mit diesem an über mehrere Zeilen irgendetwas zu zeichnen.

    Was du hier auch komplett ignorierst und vergisst, ist die klare Auftrennung von Aufgaben. Sowas hilft schlussendlich auch dem Verständnis der Bibliothek und macht sie einfach. Denn so kannst du auch eine m:1:n Beziehung aufbauen, während mit deiner aktuellen Lösung du eine m:n Beziehung hast. Wenn einmal nicht nur auf einem Bitmap gezeichnet werden soll, dann hast du ein Problem und musst zig Schnittstellen neu erstellen.

    Und die release Methode ist völlig unnötig oder SEHR optional. In C++ gibt es Destruktoren, welche solche Aufgaben allenfalls übernehmen können. Wobei ich hier allerdings gar nicht einsehe, wieso es eine solche Methode bräuchte. Das GraphicDevice kann Bitmap gleich als Model verwenden.

    KISS ist schön und gut, aber man sollte deswegen nicht anfangen schlechtes Design einzuführen. Ich hatte erst gerade letztens jemand, welcher wegen dem KISS Prinzip alle Attribute public gemacht hat. Mit der Begründung eben, dass es doch nur völlig umständlich ist, immer über Getter und Setter zu gehen. Als man seinen Code dann auch angeschaut hat, wurde klar wieso er dies als mühsam empfand, weil er die Aufgaben nicht mehr sauber getrennt hat, musste er von von völlig verkehrten Stellen auf alle Informationen einer Klasse zugreifen. Statt die Aufgaben an die Klasse auzulagern oder ein paar zusätzliche Klassen einzuführen, welche diese Aufgaben übernehmen. Der Code wirklich in Keep It Simple and Stupid gehalten.

    Probiere lieber ein gutes Design und klare Aufgabentrennung anzustreben. Sowas hilft am allermeisten dem Verständnis eines Programmcodes. Wenn jede Klasse nur eine Aufgabe erfüllt (eine Richtlinie), dann ist das Zusammenspiel der Klassen deutlich einfacher zu verstehen.

    Grüssli


Anmelden zum Antworten