В C++ Переопределение Методов

Я не могу понять, что с этим происходит.

у меня есть класс сцены, который имеет вектор сущностей и позволяет добавлять и получать сущности из сцены:

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();
};

мой класс сущности выглядит следующим образом (вывод для тестирования):

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

и тогда у меня есть класс Polygon, который наследуется от Entity:

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
};

как вы можете видеть, у него есть метод draw (), который должен переопределить метод draw (), который он наследует от сущности класс.

но это не так. При использовании следующего кода:

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

где Объект 0 является многоугольником (или, по крайней мере, должен быть), он печатает "нет" из родительского метода (как будто это не многоугольник, а просто объект). На самом деле, это не позволяет мне вызывать какие-либо методы, уникальные для Polygon, не получая:

'название метода' : не является членом 'сущности'

есть идеи, что случилось?

Спасибо за помощь.

обновление:

поэтому я реализовал код, указанный в первом ответе, но я не уверен, как добавить мой многоугольник в список. Что-то вроде этого?

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);

Я просто не привык к этому shared_ptr бизнес.

5 ответов


я думаю, что вам нужно опубликовать свой код вызова, но по существу проблема заключается в этом.

у вас есть конкретный класс Polygon вывод из другого конкретного класса Entity. Ваши функции addEntity и getEntity принимают и возвращают Entity по стоимости поэтому, если вы попытаетесь передать или получить Entity, вы будете копировать только Entity часть этого объекта (нарезка его) и информация о производной части объекта будут потерянный.

кроме того, у вас есть vector of Entity, который является вектором объектов базового класса, поэтому у вас нет возможности хранить что-либо, кроме базового типа объекта.

Если вам нужно иметь коллекцию объектов смешанного типа, но все они получены из Entity, вам может потребоваться использовать динамически созданные объекты и какой-то умный указатель, такой как tr1::shared_ptr или a boost::shared_ptr.

Э. Г.

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();
};

редактировать

ваш обновленный вызывающий код по существу корректен, хотя использование локальной ссылки const на общий указатель немного неясно.

я бы, вероятно, пошел с чем-то вроде:

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);

комментарий chollida верен: вы помещаете объект типа Polygon в место памяти, предназначенное для сущности типов, и запускаете то, что называется для нарезки. Дополнительная информация о "полигоне" отрезается, и все, что у вас осталось, - это объект.

вы должны хранить указатели (или ссылки, если это возможно) на базовые классы в этих ситуациях.


для этого следует использовать чисто виртуальную функцию.

class Entity
{
public:
    virtual void draw() = 0;
};

затем вызовите функцию draw из вашего объекта, и вы также должны использовать указатели на свои объекты.


вы должны хранить указатели (умные указатели :) предпочтительно) на экземпляры сущностей в первую очередь. Вектор перераспределяется при вставке, поэтому ваши объекты нарезаются еще до вызова метода getter.

возвращаемый тип для метода getter также должен быть указателем или ссылкой, чтобы вы могли сделать этот полиморфный вызов.


Как правило, вы всегда должны использовать ссылочную семантику (т. е. обращаться к объектам через указатели или ссылки) вместо семантики значений при работе с объектами, которые вы собираетесь использовать полиморфно.

чтобы обеспечить безопасность таким образом, разумно сделать базовый класс всех ваших полиморфных типов noncopyable путем создания частного конструктора копирования и оператора присваивания. Это эффективно предотвратит нарезку, поскольку код просто не сможет дополнить если семантика значений используется по ошибке.