Storing heterogeneous objects in vector with stack-allocated objects
Storing objects in heterogeneous vector with stack-allocated objects
Hello,
Say I have an abstract class CA, derived into CA1, CA2, and maybe others.
I want to put objects of these derived types into a vector, that I embbed into a class CB. To get polymorphism right, I need to store a vector of pointers:
class CB
{
std::vector <CA*> v;
};
Now, say I have the following main function:
int main()
{
CB b;
CA1 a1;
CA2 a2;
b.Store( a1 );
b.Store( a2 );
}
How do I write the method void CB::Store(const CA&)
in a simple way, so the stored objects survive when the original objects gets destroyed (which doesn't occur in the simple example above).
My problem is that I need to first copy objects on the heap before copying their adress in the vector, but how can I create an object of a derived type ? Sure, I could use RTTI, and search for all possible types, create and allocate a poin开发者_如何学Pythonter, and copy (with proper casting) the object into the allocated space before pushing it into the vector. But this seems quite complicated, no ?
Is there a simpler way ?
(And without using dynamic allocation in the main !)
Commonly, you will provide a clone function:
struct CA
{
virtual CA *clone(void) const = 0;
virtual ~CA() {} // And so on for base classes.
}
struct CA1 : public CA
{
virtual CA *clone(void) const
{
return new CA1(*this);
}
}
struct CA2 : public CA
{
virtual CA *clone(void) const
{
return new CA2(*this);
}
}
This is called a virtual constructor, you can construct copies of objects at runtime:
void CB::Store(const CA& pObject)
{
CA *cloned = pObject.clone();
}
You should consider using the Boost.Pointer Container library. Your code would be:
boost::ptr_vector<CA> objects;
void CB::Store(const CA& pObject)
{
objects.push_back(pObject->clone());
}
And now you have no need to manage memory yourself. The library also respects clone functions, and will call it when making copies of your objects. Tutorial here.
Sounds like you need a clone() function in your abstract class that your derived classes will implement.
class CA
{
public:
virtual ~CA() {}
virtual CA* clone() const = 0;
}
class CA1 : public CA
{
public:
virtual CA *clone() const
{
return new CA1(*this);
}
};
A possibility would be to templatize Store on the type of its argument:
class CB
{
public:
template<class T>
void Store(const T& t)
{
v.push_back(new T(t));
}
private:
std::vector <CA*> v;
};
A warning though: Unlike the "clone()" solution posted by others, this is prone to slicing. For example, this works fine:
CB b;
CA1 a1;
CA2 a2;
b.Store(a1);
b.Store(a2);
But this does not:
CA1 a1;
CA* a = &a1;
b.Store(*a); //Ouch! this creates a new CA, not a CA1
Giving a protected copy ctor to CA prevents such misuse. However, if we further subclass CA1, the issue comes back.
精彩评论