我正在研究抽象类的东西。
#include <iostream>
#include <vector>
using namespace std;
class Shape
{
protected:
int m_size;
public:
int getSize() { return m_size; }
virtual bool isEqual(Shape *rhs) = 0;
};
以下是派生类之一:
class Circle : public Shape
{
public:
Circle(int size) { m_size = size; }
bool isEqual(Shape *rhs)
{
Circle* circle = dynamic_cast<Circle*>(rhs);
if(circle == 0)
return false; // not a Circle
return m_size == circle->getSize();
}
};
我将所有形状存储在一个容器中(基本上是一个形状指针的矢量。
class Container
{
private:
vector<Shape*> v;
public:
~Container()
{
for(int i = 0; i < v.size(); i++) {
cout << "Removind element Nr. " << i << endl;
delete v[i];
}
v.erase(v.begin(), v.end());
}
bool add(Shape *shape)
{
for(int i = 0; i < v.size(); i++) {
if( v[i] == shape ) {
return false;
}
if( v[i]->isEqual(shape) ) {
return false;
}
}
v.push_back(shape);
return true;
}
};
我想知道是否可以在容器中添加元素而不将它们作为指针传递。 目前它的工作原理如下:
Container c;
c.add(new Circle(10));
我想以这种方式使用它:
C.add(Circle(10));
解决方案是什么?
答案 0 :(得分:5)
不要按值存储多态对象。这可能会导致object slicing。
在您的情况下,甚至不可能按值存储Shape
类型的对象,因为该类具有纯虚方法。
如果您想要更好的资源管理,例如自动拨打delete
,您可以使用shared_ptr
或unique_ptr
。
答案 1 :(得分:0)
如果要统一使用容器并在同一容器中保存任何类型的Shape(圆形,矩形..),则不能。例如,目前您可以使用基类指针添加任何形状。但是如果要添加对象而不是指针,则必须为每种类型声明一个容器。您将无法统一处理这些对象。
答案 2 :(得分:0)
您需要将新对象的创建移动到Container::add
,以便仅在对象不在容器中时才创建对象。实现它的一种方法是在Clone
中声明纯虚拟Shape
函数,然后在Circle
中定义它:
virtual Shape* Clone()
{
return new Circle(*this);
}
然后您可以按价值将对象传递给add
,它会调用Clone
:
v.push_back(shape.Clone());
答案 3 :(得分:0)
与克隆方法类似,
您可以通过类似(在C ++ 11中)的方式修改方法add
:
template<typename T, typename...Ts>
bool Container::add(Ts&&... args)
{
std::unique_ptr<T> newShape(new T(std::forward<Ts>(args)...));
for (const Shape* shape : v) {
const auto* shapeT = dynamyc_cast<const T*>(shape);
if (shapeT != nullptr && shapeT->isEqual(newShape) ) {
return false;
}
}
v.push_back(newShape.release()); // better to have std::vector<std::unique_ptr<Shape>>...
return true;
}
然后使用它:
c.add<Circle>(10);