Я использую ptr_vector для хранения «фигур». Я пытаюсь заполнить его производными классами фигур, такими как «круги», и каждый раз, когда я пытаюсь уменьшить их, я получаю плохой состав.
class Shape
{
public:
virtual ~Shape() {};
virtual void print() { std::cout << "shape" << std::endl; };
};
class Circle :
public Shape
{
public:
void print() { std::cout << "circle" << std::endl; };
};
int main()
{
boost::ptr_vector<Shape> shapes;
shapes.push_back(new Circle);
BOOST_FOREACH(Shape shape, shapes)
{
Circle& tempCircle = dynamic_cast<Circle&>(shape);
if(&tempCircle != NULL)
tempCircle.print();
}
system("PAUSE");
}
Проблема в том, что ваш shape
это объект, тип которого Shape
а не ссылка на объект, чей (динамический) тип Circle
,
Полиморфизм работает только со ссылками или указателями. При обработке объектов как ценности и копировать-конструировать или перемещать-конструировать объекты базового класса из объектов производного класса, что вы получите нарезка (определенно не то, что вы хотите).
Попробуйте это вместо этого:
BOOST_FOREACH(Shape& shape, shapes)
// ^
Было бы также целесообразно использовать ссылку на const
, вероятно — поскольку вы не собираетесь изменять ссылочный объект внутри цикла, поэтому:
BOOST_FOREACH(Shape const& shape, shapes)
// ^^^^^^
{
Circle const& tempCircle = dynamic_cast<Circle const&>(shape);
// ^^^^^^ ^^^^^^
// ...
}
Также обратите внимание, что C ++ 11 имеет диапазон for
петли, которые делают BOOST_FOREACH
вид устарел. Так что, если C ++ 11 является опцией, вы можете написать:
for (auto const& shape : shapes)
{
Circle const& tempCircle = dynamic_cast<Circle const&>(shape);
// ^^^^^^ ^^^^^^
// ...
}
При этом имеет смысл указать (как Чад в комментариях) что вам не нужно выполнять динамическое снижение, так как print()
это виртуальная функция. При выполнении:
shape.print();
Вызов функции будет отправлен Circle::print()
если объект, на который ссылается Shape
это пример Circle
,
Кроме того, вы не используете dynamic_cast правильно. Если вы динамически передаете ссылку, и объект на самом деле не принадлежит классу, к которому вы ее приводите, то бросок std::bad_cast
, Он не возвращает ноль, потому что нет такой вещи, как ссылка с нулевым адресом. Итак, вот правильный путь:
Circle* tempCircle = dynamic_cast<Circle*>(&shape);
if(tempCircle != NULL)
tempCircle->print();
(Вы можете на самом деле иметь ссылку r
с &r == NULL
, но только после разыменования нулевого указателя, который имеет неопределенное поведение.)