Abstrakte Klasse als Parameter/Übergabe eines temporären Objekts möglich?



  • Guten Abend.

    Ich habe eine Frage zum Übungsbeispiel Ü2 aus dem Kapitel 12.7 aus dem Buch "Die C++ Programmiersprache" von B. Stroustrup. Das Beispiel findet sich im Netz zB. unter:

    http://books.google.com/books?id=YR5CqZcFJU8C&pg=PA345&lpg=PA345&dq=%22implementieren+sie+ein+einfaches+graphiksystem%22&source=web&ots=QGwl7awg2I&sig=SCNDSMVZCFBmJnYKMOPWgOd35KU#PPA345,M1

    Ich habe versucht, aus dem Stroustrup-Beispiel den für meine Frage wesentlichen Teil (hoffentlich richtig) in ein kleines C++-Programm zu destillieren. Nachfolgend poste ich erstmal das Programm samt Fehlermeldung, anschließend folgt meine Frage:

    #include <iostream>
    
    // ==================================
    class Form
    {
    public:
        virtual ~Form() {}
        virtual void zeichne() const = 0;
    };
    
    // ==================================
    class Punkt: public Form
    {
    public:
        virtual ~Punkt() {}
        virtual void zeichne() const
        {
            std::cout << "Punkt" << std::endl;
        }
    };
    
    // ==================================
    void draw(Form * f)
    {
        std::cout << "zeichne ";
        f->zeichne();
    }
    
    // ==================================
    int main()
    {
        Form * p1 = new Punkt;
        draw(p1);
        delete p1;
    
        Punkt p2;
        draw(&p2);
    
        draw(new Punkt()); // geht, aber wer gibt Speicher frei?
        draw(&Punkt());    // Warnung: Referenz auf temporäres Objekt
        draw(Punkt());     // Fehler: cannot convert Punkt to Form*
    }
    

    Ausgabe beim Kompilieren mit djgpp:

    D:\cpp>gpp test.cpp -o test.exe -Wall
    test.cpp: In function 'int main()':
    test.cpp:40: warning: taking address of temporary
    test.cpp:41: error: cannot convert 'Punkt' to 'Form*' for argument '1' to 'void
    draw(Form*)'
    

    Meine Frage:
    In der Angabe des Beispiels kommt folgende Anweisung vor:

    f.zeichne(Kreis(...))

    f.zeichne() sei dabei eine Funktion, die ein Form-Objekt veranlasst, sich zu zeichnen, in meinem Programm ist das die Funktion draw(). Kreis(...) ist ein temporäres Form-Objekt. Der zitierten Anweisung entspricht mE. die Zeile 41 in meinem Programm, die logischerweise fehlschlägt.

    Eine Lösung wäre sicherlich, eine draw(Punkt p)-Funktion zu schreiben, ich kann mir aber nicht vorstellen, dass dieser umständliche Weg tatsächlich gemeint war, oder verstehe ich da was falsch?

    Vorweg herzlichen Dank für jede Unterstützung.
    Roland



  • Thoreau schrieb:

    Abstrakte Klasse als Parameter/Übergabe eines temporären Objekts möglich?

    Ja.

    Punkt p2; // <-- ein temporäres Objekt p2
        draw(&p2); // <-- übergabe als Parameter
    


  • Danke.

    Ich hab mich wohl missverständlich ausgedrückt durch die Frage im Titel. Meine tatsächliche Frage (im ersten Posting ganz unten) hängt zwar damit zusammen, ist aber anders gelagert.

    Eine Lösung wäre sicherlich, eine draw(Punkt p)-Funktion zu schreiben, ich kann mir aber nicht vorstellen, dass dieser umständliche Weg tatsächlich gemeint war, oder verstehe ich da was falsch?

    Any ideas?

    lg
    Roland



  • @Thoreau: ersetze doch bitte den elendslangen link, der die seitendarstellung etwas in die breite zieht durch diesen hier: http://tinyurl.com/36wp89

    Ramsis schrieb:

    Punkt p2; // <-- ein temporäres Objekt p2
        draw(&p2); // <-- übergabe als Parameter
    

    Punkt p2 ist allerdings kein temporäres objekt.

    draw(Punkt());
    

    so wird ein temporäres objekt erzeugt.
    temporäre objekte binden an konstante referenzen. deklariere deine funktion draw also so:

    void draw (Form const& f)
    {
       //...
       f.draw();
    }
    

    beachte dabei, dass die elementfunktion draw selbst konstant sein muss. (es gibt dafür nur einen hässlichen workaround)

    also so:

    class Punkt
    {
      virtual void draw () const = 0;
     //...
    };
    


  • queer_boy schrieb:

    @Thoreau: ersetze doch bitte den elendslangen link, der die seitendarstellung etwas in die breite zieht durch diesen hier: http://@notallowed@.com/36wp89

    @queer_boy: Dein Link funktioniert bei mir nicht. Also draufklicken geht nicht, wenn ich die Verknüpfung kopier und händisch im Browser einfüg, dann geht's schon.

    lg
    Roland



  • oh, anscheinend zensiert das forum tinyurls..



  • @queer_boy: Herzlichen Dank für deine Anregungen und die prompte Hilfe.

    Ist eigentlich eh völlig klar, ich hab's mit Referenz schon probiert, aber da dürft ich was anderes falsch gemacht haben.

    Habe nun eine zweite draw()-Funktion mit const Referenz (Zeilen 41ff.) neben die draw() mit Pointer als Parameter (Zeilen 34ff.) gestellt, jetzt klappt alles wunderbar (siehe Programm Zeilen 66 und 67).

    Das reparierte (und um Klasse Linie erweiterte) Programm schaut nun so aus:

    #include <iostream>
    
    // ==================================
    class Form
    {
    public:
        virtual ~Form() {}
        virtual void zeichne() const = 0;
    };
    
    // ==================================
    class Punkt: public Form
    {
    public:
        virtual ~Punkt() {}
        virtual void zeichne() const
        {
            std::cout << "Punkt" << std::endl;
        }
    };
    
    // ==================================
    class Linie: public Punkt
    {
    public:
        virtual ~Linie() {}
        virtual void zeichne() const
        {
            std::cout << "Linie" << std::endl;
        }
    };
    
    // ==================================
    void draw(const Form * const f)
    {
        std::cout << "zeichne (*) ";
        f->zeichne();
    }
    
    // ==================================
    void draw(const Form & f)
    {
        std::cout << "zeichne (&) ";
        f.zeichne();
    }
    
    // ==================================
    int main()
    {
        Form * p1 = new Punkt;
        draw(p1);
        delete p1;
    
        Form * l1 = new Linie;
        draw(l1);
        delete l1;
        std::cout << std::endl;
    
        Punkt p2;
        draw(p2);
    
        Linie l2;
        draw(l2);
        std::cout << std::endl;
    
        draw(Punkt());
        draw(Linie());
    }
    

    Die Ausgabe dazu:

    D:\cpp>test
    zeichne (*) Punkt
    zeichne (*) Linie
    
    zeichne (&) Punkt
    zeichne (&) Linie
    
    zeichne (&) Punkt
    zeichne (&) Linie
    

    lg
    Roland



  • Hallo Thoreau,

    du bist zwar auf dem richtigen Weg, hast aber für die gesamte Aufgabe noch ein paar Erweiterungen vor dir.
    Zuerst einmal solltest du noch die Klasse Fenster definieren und dort dann die Methode 'zeichne' implementieren (anstatt als freie Funktion):

    class Fenster
    {
    public:
      void zeichne(const Form &form);
    };
    

    Dann benötigt jede deiner Form-Klassen noch entsprechende Parameter beim jeweiligen Konstruktor für die Angabe der Positionen, z.B.

    class Position
    {
    public:
      Position(int x, int y);
      // ...
    };
    
    class Linie : public Form
    {
    public:
      Linie(const Position &p1, const Position &p2);
    };
    
    // weitere Form-Klassen mit Konstruktor
    // ...
    

    Viel Erfolg noch bei der Aufgabe (*3,5), welche ja als sehr umfangreich eingestuft ist.

    Mit welchem Grafiksystem willst du denn die Forms (real) zeichnen, oder hast du eine reine Konsolenanwendung?



  • Hallo Th,

    danke für deine Tipps, aber das habe ich alles schon längst. Es zeichnet alles auch schon brav (reine Konsolenanwendung, Bresenham-Algorithmus zum Linienzeichnen usw.).

    Mir ging es tatsächlich nur darum, den Fall draw(Punkt(...)) hinzubekommen (hatte ich eigentlich auch schon, funktionierte aber nicht wegen eines anderen Fehlers, den ich offenbar dann behoben und dadurch wieder was gelöscht hatte... die Tücken der Nacht halt... ;))

    Thoreau schrieb:

    Ich habe versucht, aus dem Stroustrup-Beispiel den für meine Frage wesentlichen Teil (hoffentlich richtig) in ein kleines C++-Programm zu destillieren.

    Ich wollte dem Forum nicht mein ausführliches Programm zumuten, sondern meine Frage mit einem hilfreichen Destillat illustrieren (ging ja nur um das Prinzip). Ich lerne seit Herbst C++ und wollte das Stroustrup-Beispiel als Training nutzen (hab viel dabei gelernt).

    Danke für die nette Art der Hilfestellung in diesem Forum. 👍

    lg
    Roland


Anmelden zum Antworten