Klausurfrage



  • Hallo zusammen!

    Ich lerne gerade für eine Klausur und komme bei folgendem Übungsbeispiel einfach nicht weiter. Ich soll 5 Fehler finden, beschreiben worin genau der Fehler besteht, sowie Korrekturvorschläge erbringen. Jedoch schon beim Finden der Fehler scheitere ich. Vielleicht könnt ihr mir helfen.
    Der Code lautet:

    #include <iostream>
    #include <vector>
    struct Point {
        Point() : x(0.0), y(0.0) {}
        Point(double px, double py) : x(px), y(py) {}
        double x;
        double y;
    };
    
    class Shape {
    public:
        virtual void move(double deltax, double deltay) = 0;
        virtual void print() = 0;
    };
    
    class Polygon : public Shape {
    public:
        Polygon(int vertices) {
            m_ptrVertices = new Point[vertices];
            m_nvertices = vertices;
        }
        Polygon(const Polygon& from) : m_nvertices(from.m_nvertices) {
            m_ptrVertices = new Point[m_nvertices];
            for(int i = 0; i < m_nvertices; ++i) {
                m_ptrVertices[i] = from.m_ptrVertices[i];
            }
        }
        Polygon& operator=(const Polygon& from) {
            if(&from != this) {
                m_ptrVertices = new Point[m_nvertices];
                for(int i = 0; i < m_nvertices; ++i) {
                    m_ptrVertices[i] = from.m_ptrVertices[i];
                }
            }
        }
    
        ~Polygon() {delete[] m_ptrVertices;}
    
        void setPoint(int i, const Point& point) {
            if (i >=0 && i<m_nvertices) {
                m_ptrVertices[i] = point;
            }
        }
    
        void print() {
            for(int i = 0; i < m_nvertices; ++i) {
            std::cout << m_ptrVertices[i].x << ", " << m_ptrVertices[i].y <<  std::endl;
            }
            std::cout << std::endl;
        }
    
    private:
        int m_nvertices;
        Point* m_ptrVertices;
    };
    
    int main() {
        Polygon triangle(3);
        triangle.setPoint(0, Point(0,0));
        triangle.setPoint(1, Point(1,0));
        triangle.setPoint(2, Point(0.5,1));
    
        triangle.print();
    
        Polygon triangle2(triangle);
        triangle2.print();
    
        Shape* pshape = new Polygon(1);
        *pshape = triangle;
        pshape->print();
        delete pshape;
    
        return 0;
    }
    


  • Welche Fehler findest du denn? Ansonsten ein Tipp: 4 von 5 haben mit der Zuweisung zu tun.



  • So auf die ersten paar Blicke:

    Falsch: Verwendung von ungarischer Notation

    Point* m_ptrVertices;
    

    Falsch: C-Array (richtig: std::vector)

    class Shape {
    public:
        virtual void move(double deltax, double deltay) = 0;
        virtual void print() = 0;
    };
    

    Falsch: kein virtueller Destruktor

    Polygon(int vertices)
    

    Falsch: nicht "explicit"

    class Polygon : public Shape {
    

    Falsch: "move" nicht implementiert



  • Fragwürdigen oder veralteten Stil würde ich nicht als Fehler im eigentlichen Sinne bezeichnen.

    Aber immerhin sind es jetzt 6, das mit dem virtuellen Destruktor hatte ich nicht gesehen. Ist das wirklich eine Klausuraufgabe? Kommt mir sagen wir mal untypisch vor.

    Meine Liste:
    move nicht implementiert, dadurch ist Polygon nicht instanziierbar
    Zuweisung *pshape = ... nicht möglich, weil Shape keinen Zuweisungsoperator hat
    Zuweisungsoperator von Polygon: hat kein return, gibt den alten Speicher nicht frei, übernimmt die Anzahl der Punkte nicht von from
    virtueller Destruktor fehlt



  • Bashar schrieb:

    Zuweisung *pshape = ... nicht möglich, weil Shape keinen Zuweisungsoperator hat

    Und wenn er ihn hätte, würde es zu Slicing kommen. Muss kein Fehler sein, aber i.d.R. will man bei sowas polymorphes Verhalten, schließlich wird anschließend eine rein virtuelle Methode aufgerufen (pshape->print()). Dies würde dann einen "pure virtual function call" ergeben, weil pshape auf ein Objekt vom Typ "Shape" zeigt.



  • daddy_felix schrieb:

    Bashar schrieb:

    Zuweisung *pshape = ... nicht möglich, weil Shape keinen Zuweisungsoperator hat

    Und wenn er ihn hätte, würde es zu Slicing kommen. Muss kein Fehler sein, aber i.d.R. will man bei sowas polymorphes Verhalten, schließlich wird anschließend eine rein virtuelle Methode aufgerufen (pshape->print()). Dies würde dann einen "pure virtual function call" ergeben, weil pshape auf ein Objekt vom Typ "Shape" zeigt.

    Nein, das Objekt ist vom Typ Polygon, und das wird sich durch die Zuweisung nicht ändern.



  • oh, das wusste ich nicht. Aber Slicing tritt trotzdem auf, oder?



  • Wenn der Operator nicht virtuell ist, ja. Zuweisung und Polymorphie passen allgemein nur schlecht zusammen.



  • #include <iostream>
    //Warnung: unnötiges include
    #include <vector>
    struct Point {
        Point() : x(0.0), y(0.0) {}
        Point(double px, double py) : x(px), y(py) {}
        double x;
        double y;
    };
    
    class Shape {
    public:
        //Fehler**: virtueller Destruktor fehlt
        virtual void move(double deltax, double deltay) = 0;
        virtual void print() = 0; //Fehler: const fehlt
    };
    
    class Polygon : public Shape {
    public:
        //Warnung: Standardkonstruktor fehlt
    
        Polygon(int vertices) {
            //Fehler: explicit fehlt
            //Fehler: int ist der falsche Typ
            //Fehler: Initialisierungsliste fehlt
            m_ptrVertices = new Point[vertices];
            m_nvertices = vertices;
        }
        Polygon(const Polygon& from) : m_nvertices(from.m_nvertices) {
            //Fehler: Initialisierungsliste fehlt
            m_ptrVertices = new Point[m_nvertices];
            for(int i = 0; i < m_nvertices; ++i) {
                m_ptrVertices[i] = from.m_ptrVertices[i];
            }
        }
        Polygon& operator=(const Polygon& from) {
            if(&from != this) {
                //Fehler**: m_nvertices wird nicht kopiert
                m_ptrVertices = new Point[m_nvertices]; //Fehler: Speicherleck
                for(int i = 0; i < m_nvertices; ++i) {
                    m_ptrVertices[i] = from.m_ptrVertices[i];
                }
            }
            //Fehler**: return fehlt
        }
    
        ~Polygon() {delete[] m_ptrVertices;}
    
        void setPoint(int i, const Point& point) {
            if (i >=0 && i<m_nvertices) { //Fehler: Benutzungsfehler wird verschleiert
                m_ptrVertices[i] = point;
            }
        }
    
        void print() {
            //Warnung: der ostream kann nicht als Argument angegeben werden
            for(int i = 0; i < m_nvertices; ++i) {
            std::cout << m_ptrVertices[i].x << ", " << m_ptrVertices[i].y <<  std::endl; //Fehler: unnötiges flush
            }
            std::cout << std::endl; //Warnung: unnötige Leerzeile
        }
    
        //Fehler**: move-Methode fehlt
    
    private:
        int m_nvertices;
        Point* m_ptrVertices; //Fehler: ein besitzender, roher Zeiger
    };
    
    int main() {
        Polygon triangle(3);
        triangle.setPoint(0, Point(0,0));
        triangle.setPoint(1, Point(1,0));
        triangle.setPoint(2, Point(0.5,1));
    
        triangle.print();
    
        Polygon triangle2(triangle);
        triangle2.print();
    
        Shape* pshape = new Polygon(1); //Fehler: ein besitzender, roher Zeiger
        *pshape = triangle; //Fehler**: Zuweisung ergibt so keinen Sinn
        pshape->print(); //Fehler: Speicherleck falls das wirft
        delete pshape;
    
        return 0; //Warnung: unnötig
    }
    

    Mit Fehler** sind die fünf markiert, die womöglich in der Aufgabe gemeint sind.


Log in to reply