С++ переопределенный метод, не вызываемый
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.
Также соблюдайте ответственность за управление памятью (правильно
письменные деструкторы и т.д.).
Ответ 7
Вы можете попробовать boost:: ptr_vector
http://www.boost.org/doc/libs/1_40_0/libs/ptr_container/doc/ptr_container.html
Ответ 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;). потому что я иногда забывал об этом, поэтому я уловил его как синтаксическую ошибку.