С++ переопределенный метод, не вызываемый

Shape.h

namespace Graphics {
    class Shape {
    public:
        virtual void Render(Point point) {};
    };
}

Rect.h

namespace Graphics {
    class Rect : public Shape {
    public:
        Rect(float x, float y);
        Rect();
        void setSize(float x, float y);
        virtual void Render(Point point);

    private:
        float sizeX;
        float sizeY;
    };
}

struct ShapePointPair {
    Shape shape;
    Point location;
};

Используется так:

std::vector<Graphics::ShapePointPair> theShapes = theSurface.getList();

for(int i = 0; i < theShapes.size(); i++) {
    theShapes[i].shape.Render(theShapes[i].location);
}

Этот код в конечном итоге вызывает Shape::Render а не Rect::Render

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

Есть идеи, как этого добиться?

Ответ 1

Вот ваша проблема:

struct ShapePointPair {
        Shape shape;
        Point location;
};

Вы сохраняете Shape. Вы должны хранить Shape * или shared_ptr<Shape> или что-то еще. Но не Shape; С++ не является Java.

Когда вы назначаете Rect для Shape, копируется только часть Shape (это срез объектов).

Ответ 2

Эта проблема называется slicing - вы теряете производную функциональность при копировании на базу. Чтобы избежать этого, используйте указатели на базовый класс, то есть

std::vector<Graphics::Shape*> s;
s.push_back(&some_rect);

Ответ 3

Проблема заключается в том, что в вашем векторе вы сохраняете копии объектов Shape, а копирование объекта Shape не копирует данные или функциональные возможности его производных классов - вы slicing полиморфизм.

Управляйте объектами с помощью new и delete и организуйте для своего вектора сохранение указателей на них.

Ответ 4

Полиморфизм будет работать только от указателя на фигуру, а не от объекта формы.

Ответ 5

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

Например, когда вы назначаете Shape в ShapePointPair, код будет "обрезать" объект и только скопировать бит формы в ShapePointPair

Выполнение этого будет означать, что вам нужно следить за управлением памятью - чтобы вы могли использовать интеллектуальный указатель в структуре   ShapePointPair {          форму smart_pointer;           Местоположение точки;   };

Ответ 6

Нет, это не кастинг.

Вместо этого вы можете сохранить ссылку на базовый класс Point:

struct ShapePointPair {
        Shape shape;
        Point &location;
};

Эта ссылка должна быть установлена ​​во время построения для структуры ShapePointPair. Добавьте конструктор в ShapePointPair для этого цель. Необходимо передать (вновь созданные) экземпляры Rect.

Также соблюдайте ответственность за управление памятью (правильно письменные деструкторы и т.д.).

Ответ 8

Я не очень хорошо объясню, потому что мой английский плохой.

Я думаю, вам следует использовать его ссылку или тип указателя. потому что форма точно определяет, что она должна делать.

Если вы используете свой код напрямую, ваш ребенок попытается скопировать и сделать работу. Вот почему не работает ваша функция переопределения.

используйте указатель или ссылку, как это.

pointer.h

class Parent {
public:
    virtual void work() { printf("parent is working now\n"); }
};
class Child1 {
public:
    virtual void work() { printf("child1 is working now\n"); }
};
class Child2 {
public:
    virtual void work() { printf("child2 is working now\n"); }
};
struct Holder {
    Parent* obj1;
    Parent* obj2;
};
int main() {
    Child1 child1;
    Child2 child2;
    Holder holder = { &child1, &child2 };
    holder.obj1->work();
    holder.obj2->work();
    return 0;
}

reference.h

class Parent {
public:
    virtual void work() { printf("parent is working now\n"); }
};
class Child1 {
public:
    virtual void work() { printf("child1 is working now\n"); }
};
class Child2 {
public:
    virtual void work() { printf("child2 is working now\n"); }
};
struct Holder {
    Parent& obj1;
    Parent& obj2;
};
int main() {
    Child1 child1;
    Child2 child2;
    Holder holder = { child1, child2 };
    holder.obj1.work();
    holder.obj2.work();
    return 0;
}

* ps: лично я использую абстрактную функцию (virtual void something() = 0;). потому что я иногда забывал об этом, поэтому я уловил его как синтаксическую ошибку.