Reputation: 49
I am working on something with abstract class.
#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;
};
Here is one of the derived class:
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();
}
};
And I store all shapes in a container (basically a vector of pointer of shape.
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;
}
};
I would like to know if it is possible to add element in the container without passing them as pointer. Currently it works like that:
Container c;
c.add(new Circle(10));
And I would like to use it in this way:
C.add(Circle(10));
What would be the solution?
Upvotes: 1
Views: 142
Reputation: 217145
Similar to the clone method,
You can modify your method add
by something like (in C++11):
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;
}
And then use it like:
c.add<Circle>(10);
Upvotes: 0
Reputation: 20993
You need to move creation of the new object to the Container::add
so the object is created only if it is not in the container. One way to achieve it is to declare the pure virtual Clone
function in Shape
and then define it in Circle
:
virtual Shape* Clone()
{
return new Circle(*this);
}
Then you can pass the object by value to add
, and it will call Clone
:
v.push_back(shape.Clone());
Upvotes: 0
Reputation: 7625
You can not if you want to use the container uniformly and save any type of Shape (circle,rectangle ..) in the same container. For example, currently you can add any shape by using the base class pointer. But if you want to add object, not pointer, you have to declare one container for each type. You will not be able to handle the objects uniformly.
Upvotes: 0
Reputation: 22981
Don't store polymorphic objects by value. This may result in object slicing.
In your case it is not even possibly to store objects of type Shape
by value because the class has pure virtual methods.
If you want better resource management, e.g. automatically calling delete
, you can use shared_ptr
or unique_ptr
.
.
Upvotes: 5