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 pointer, 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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.