Question

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 !)

Was it helpful?

Solution

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.

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top