2009-08-04 8 views
7

Ich kann nicht herausfinden, was los ist.C++ Overriding Methoden

ich eine Szene Klasse, die einen Vektor von Entitäten hat und ermöglicht es Ihnen, Objekte aus der Szene hinzuzufügen und zu erhalten:

class Scene { 
    private: 
     // -- PRIVATE DATA ------ 
     vector<Entity> entityList; 
    public: 
     // -- STRUCTORS --------- 
     Scene(); 
     // -- PUBLIC METHODS ---- 
     void addEntity(Entity); // Add entity to list 
     Entity getEntity(int); // Get entity from list 
     int entityCount(); 
}; 

Meine Entity-Klasse ist wie folgt (Ausgabe ist zum Testen):

class Entity { 
    public: 
     virtual void draw() { cout << "No" << endl; }; 
}; 

Und dann habe ich eine Polygon-Klasse, die von Entity erbt:

class Polygon: public Entity 
{ 
    private: 
     // -- PRIVATE DATA ------ 
     vector<Point2D> vertexList; // List of vertices 
    public: 
     // -- STRUCTORS --------- 
     Polygon() {}; // Default constructor 
     Polygon(vector<Point2D>); // Declare polygon by points 
     // -- PUBLIC METHODS ---- 
     int vertexCount(); // Return number of vertices 
     void addVertex(Point2D); // Add vertex 
     void draw() { cout << "Yes" << endl; }; // Draw polygon 
     // -- ACCESSORS --------- 
     Point2D getVertex(int); // Return vertex 
}; 

Wie Sie kann sehen, es hat eine draw() -Methode, die die draw() -Methode überschreiben sollte, die es von der Entity-Klasse erbt.

Aber es tut es nicht. Wenn mit dem folgenden Code:

scene->getEntity(0).draw(); 

wo Entität 0 ein Polygon (oder zumindest sein soll), druckt er „Nein“ von der übergeordneten Methode (als ob es kein Polygon ist, nur eine Entity). In der Tat scheint es nicht mich eindeutig Polygon alle Methoden zu lassen rufen, ohne sich:

einige Methodennamen‘: ist jede Idee kein Mitglied von ‚Entity‘

Also, was ist los?

Danke für die Hilfe.

UPDATE:

Also habe ich den Code in der ersten Antwort gegeben implementiert, aber ich bin nicht sicher, wie mein Polygon zur Liste hinzuzufügen. Etwas wie das?

const tr1::shared_ptr<Entity>& poly = new Polygon; 
poly->addVertex(Point2D(100,100)); 
poly->addVertex(Point2D(100,200)); 
poly->addVertex(Point2D(200,200)); 
poly->addVertex(Point2D(200,100)); 
scene->addEntity(poly); 

Ich bin nur nicht zu diesem shared_ptr Geschäft gewöhnt.

+1

versuchen Sie, Zeiger auf Entitäten und nicht auf Kopien von Entitätsobjekten in Ihrer Scene-Klasse zu speichern. – chollida

Antwort

14

Ich denke, dass Sie Ihren aufrufenden Code veröffentlichen müssen, aber das im Wesentlichen Problem ist dies.

Sie haben eine Betonklasse Polygon, abgeleitet von einer anderen Betonklasse Entity. Ihre addEntity- und getEntity-Funktionen übernehmen und geben als Wert zurück. Wenn Sie versuchen, Entity zu übergeben oder abzurufen, kopieren Sie nur den Entity Teil dieses Objekts (Slicing) und die Informationen über den abgeleiteten Teil des Objekts wird verloren sein.

Zusätzlich haben Sie eine vector von Entity, die ein Vektor von Basisklassenobjekten ist, so dass Sie keine andere Möglichkeit haben, als den Basistyp des Objekts zu speichern.

Wenn Sie eine Sammlung von einer gemischten Art von Objekten haben müssen, aber alle abgeleitet von Entity, können Sie dynamisch erstellte Objekte und eine Art von Smart-Pointer wie ein tr1::shared_ptr oder boost::shared_ptr verwenden müssen.

z.

class Scene { 
    private: 
     // -- PRIVATE DATA ------ 
     vector< std::tr1::shared_ptr<Entity> > entityList; 
    public: 
     // -- STRUCTORS --------- 
     Scene(); 
     // -- PUBLIC METHODS ---- 
     void addEntity(const std::tr1::shared_ptr<Entity>&); // Add entity to list 
     const std::tr1::shared_ptr<Entity> getEntity(int); // Get entity from list 
     int entityCount(); 
}; 

bearbeiten

Ihre aktualisierte Telefonvorwahl ist im Wesentlichen richtig, einen lokalen const Verweis auf einen gemeinsamen Zeiger ein bisschen dunkel ist, obwohl verwenden.

ich wahrscheinlich mit so etwas wie gehen würde:

std::tr1::shared_ptr<Polygon> poly(new Polygon); 
poly->addVertex(Point2D(100,100)); 
poly->addVertex(Point2D(100,200)); 
poly->addVertex(Point2D(200,200)); 
poly->addVertex(Point2D(200,100)); 
scene->addEntity(poly); 
+3

Oder, um es grafischer zu machen, der gepostete Code nimmt ein Polygon und legt es in eine Entity-Größe, und es passt nicht alles. –

+0

Das OP wurde mit einer Frage zu diesem neuen Code aktualisiert. –

+0

Jetzt ist das Problem, dass addVertex() ist einzigartig für Polygon: Fehler C2039: 'addVertex': ist kein Mitglied von 'Entität' Danke für die große Hilfe. (Sorry, ich bin mir nicht sicher, ob ich diese zusätzlichen Fragen in Kommentaren posten sollte) –

1

chollida Kommentar ist richtig: Sie schieben ein Objekt vom Typ Polygon in eine Speicherstelle für Typen Entity gemeint, und laufen in dem, was genannt wird Schneiden. Die zusätzlichen "Polygon" -Infos werden abgeschnitten und alles, was Sie noch haben, ist die Entity.

Sie sollten Zeiger (oder Referenzen, wenn möglich) zu Basisklassen in diesen Situationen speichern.

0

Sie sollten Zeiger (Smart Pointer :) vorzugsweise zuerst an Entity-Instanzen speichern. Der Vektor wird beim Einfügen neu zugewiesen, sodass Ihre Objekte in Scheiben geschnitten werden, noch bevor die Getter-Methode aufgerufen wird.

Rückgabetyp für Getter-Methode sollte auch ein Zeiger oder eine Referenz sein, so dass Sie in der Lage sein werden, diesen polimorphen Anruf zu machen.

1

Sie sollten dafür eine reine virtuelle Funktion verwenden.

Dann rufen Sie die Zeichenfunktion von Ihrem Objekt, und Sie sollten auch Zeiger auf Ihre Objekte verwenden.

+0

> Sie sollten eine reine virtuelle Funktion dafür verwenden. Nicht unbedingt. Die Entity-Klasse könnte sicherlich eine konkrete Draw-Methode haben. – chollida

0

Als Faustregel sollten Sie bei der Verwendung von Objekten, die Sie polymorph verwenden möchten, immer die Referenzsemantik verwenden (d. H. Auf Objekte über Zeiger oder Referenzen zugreifen), anstatt die Wertesemantik.

Um auf diese Weise Sicherheit zu gewährleisten, sollten Sie die Basisklasse aller polymorphen Typen noncopyable erstellen, indem Sie einen privaten Kopierkonstruktor und einen Zuweisungsoperator erstellen. Dies verhindert effektiv das Slicing, da der Code einfach nicht kompiliert, wenn die Wertesemantik irrtümlich verwendet wird.