У меня есть абстрактный базовый класс под названием Shape, от которого происходят как Circle, так и Rectangle, но когда я выполняю следующий код в VS 2005, я получаю сообщение об ошибке Debug assertion failed. При этом я не перегружал оператор == ни в одном классе
Выражение: Векторный итератор не может быть разыменован, в чем причина.
vector<Shape*> s1;
s1.push_back(new Circle(point(1,2),3));
s1.push_back(new Circle(point(4,3),5));
s1.push_back(new Rectangle(point(1,1),4,5));
vector<Shape*> s2(s1);
reverse(s1.begin(),s1.end());
(*find(s1.begin(),s1.end(),new Circle(point(1,2),3)))->move(point(10,20));





Простой :
Чтобы он работал так, как вы хотите, вам нужно сравнивать Shape, а не Shape *
Как указано в других ответах, boost :: ptr_vector - простой способ добиться этого.
Как предлагает @David Pierre: find основан на значении: он ищет в диапазоне итераторов указатель (например, 0x0F234420), который равен указателю на только что созданный new Circle(point(1,2),3). Поскольку это новый объект, его там не будет.
Вы можете обойти это, используя find_if с оператором, который сравнивает объекты, на которые ссылается указатель.
Однако Criterium должен уметь различать типы фигур.
class Shape {
public:
//amongst other functions
virtual bool equal( const Shape* ) const = 0;
};
class Circle : public Shape {
public:
bool equal( const Shape* pOther ) const {
const Circle* pOtherCircle = dynamic_cast<const Circle*>( pOther );
if ( pOtherCircle == NULL ) return false;
// compare circle members
}
};
class Rectangle : public Shape {
public:
bool equal( const Shape* pOther ) const {
const Rectangle* pOtherR = dynamic_cast<const Rectangle*>( pOther );
if ( pOtherR == NULL ) return false;
// compare rectangle members
}
};
Shape* pFindThis = new Circle(point(1,2),3);
vector<Shape*>::const_iterator itFound = find_if (s1.begin(),s1.end(),
bind1st( mem_fun( &Shape::equal ), pFindThis) ) );
delete pFindThis; //leak resolved by Mark Ransom - tx!
if ( itFound != s1.end() ) {
(*itFound)->move(point(10,20));
}
Удаляет ли bind1st второй параметр, когда это будет сделано? В противном случае у вас утечка памяти. Я думаю, вам просто нужен местный временный член.
Это хорошая причина использовать boost :: ptr_vector.
Он не только обрабатывает тот факт, что ваши объекты должны быть уничтожены. xtofl @: Вы забыли виртуальный деструктор.
Но это также делает члены похожими на объекты, возвращая ссылки, а не указатели. Это позволяет вам использовать стандартные алгоритмы гораздо более естественно, вместо того, чтобы играть с указателями в вашей функции «равенства» (что очень не похоже на C++).
#include <boost/ptr_container/ptr_vector.hpp>
#include <iostream>
class Shape
{
public:
~Shape() {}
bool operator==(Shape const& rhs) const
{
if (typeid(*this) != typeid(rhs))
{
return false;
}
return this->isEqual(rhs);
}
private:
virtual bool isEqual(Shape const& rhs) const = 0;
};
class Circle: public Shape
{
public:
Circle(int r)
:radius(r)
{}
private:
virtual bool isEqual(Shape const& r) const
{
Circle const& rhs = dynamic_cast<Circle const&>(r);
return radius == rhs.radius;
}
int radius;
};
class Rectangle: public Shape
{
public:
Rectangle(int h,int w)
:height(h)
,width(w)
{}
private:
virtual bool isEqual(Shape const& r) const
{
Rectangle const& rhs = dynamic_cast<Rectangle const&>(r);
return (height == rhs.height) && (width == rhs.width);
}
int height;
int width;
};
int main()
{
boost::ptr_vector<Shape> data;
data.push_back(new Circle(5));
data.push_back(new Circle(6));
data.push_back(new Rectangle(7,4));
boost::ptr_vector<Shape>::iterator f;
f = find(data.begin(),data.end(),Circle(6));
std::cout << "Find(" << (f - data.begin() ) << ")" << std::endl;
}
Кажется немного опасным полагаться на operator == для проверки того, что формы имеют один и тот же тип перед вызовом isEqual. Я бы предпочел видеть эту проверку внутри самого isEqual, как это сделал xtofl.
Я предпочитаю это в 'operator ==', чтобы код не повторялся. Зачем вам это нужно в isEqual? Примечание. Форма - это чисто виртуальный объект, экземпляров быть не может. Я не понимаю, почему вы думаете, что это дангрорус?
У меня есть одно сомнение относительно проверки типов в базовых классах. Зачем это вообще нужно? Поскольку вызов для исправления функции isEqual разрешается во время выполнения из-за полиморфизма.
sirishkumar.myopenid.com @ Я допускаю, что это, наверное, ранняя оптимизация. Но если вы не проверяете 'operator ==', тогда каждая версия isEqual () также должна явно подтверждать, что параметр типа 'rhs', требуя dynamic_cast <> () и проверку исключения bad_cast или NULL.
А для сравнения объектов Shape, а не указателя формы, используйте boost :: ptr_vector. Это позволяет более естественно использовать обычные алгоритмы.