Create a data member vector of polymorphic objects

2019-04-11 15:35发布

问题:

I have an inheritance hierarchy where A is an abstract base class and B and C are polymorphic children.

I wish to have a vector class data member, on the heap, which can contain B and C objects.

So in the header file I have my

vector<A*> polymorphicobjs;

and in the constructor I tried to do:

polymorphicobjs = new vector<A>();

but obviously this wouldn't work. How do I achieve this?

回答1:

You shouldn't worry about keeping a std::vector of raw pointers. It will create a lot of hassles for you later on making sure you delete objects at the right time. What you should do is store a container of "managed" polymorphic objects (using smart pointers). Declare your vector:

std::vector<std::unique_ptr<A>> polymorphicobjs;

And now you can store polymorphic objects in the vector pretty easily (where B is a subclass of A):

polymorphicobjs.push_back(std::unique_ptr<B>(new B));

With this, you don't need to ever worry about calling delete on the objects in your vector. As soon as you "let go" of the vector (eg, when it goes out of scope in your function or it's automatically destructed if it's a class member), the objects will be deleted. The vector uniquely owns the objects.

But I need to share the objects with other code?!

If that's the case, then std::unique_ptr isn't the right choice. We can express that the objects are shared by using std::shared_ptr:

std::vector<std::shared_ptr<A>> polymorphicobjs;
// [...]
polymorphicobjs.push_back(std::make_shared<B>());

Why does the push_back look different for unique and shared?

Because C++14 isn't out yet. If you're lucky enough to use a new enough compiler (bleeding edge clang/gcc/VS2013), the unique version will look very similar:

// C++14
std::vector<std::unique_ptr<A>> polymorphicobjs;
// [...]
polymorphicobjs.push_back(std::make_unique<B>());


回答2:

I really suggest that you stick to shared_pointers either from the standard if C++11 is an options or the boost ones.

Your basic problem is that you declared a vector of pointers not a pointer to a vector

vector<T*> vec1;// a vector of pointers
vec1.push_back(new T); // add a pointer to our vector

vector<T*>* vec2; //a pointer to a vector of pointers
vec2 = new vector<T>; // create the vector on the heap
vec2->push_back(new T); // add pointer.

As I said this is most probably not what you want. You should use smart pointers.

vector<std::shared_ptr<A>> vec;
vec.push_back(std::make_shared<B>());


回答3:

Why do you want to do a new?

This line:

vector<A*> polymorphicobjs;

Already initializes your vector... After that, you can do:

polymorphicobjs.push_back( an_object );

If you really want to put it on the heap, change your declaration to:

vector<A*>* polymorphicobjs;
//        ^

But I don't think it is necessary...



回答4:

You can achieve this as you can with any other type:

int i = new int; // Error
int *pi = new int; // works!

If vector<A*> confuses you try to use this:

typedef vector<A*> vectorOfA;
vectorOfA v = new vectorOfA; // Error
...                          // guess what will work?

So problem that your polymorphicobjs is a vector of pointers, not pointer to such vector.



回答5:

You don't need to new your vector. I suspect you have come from Java, where everything needs a new. C++ is different. Simply having a vector<A*> polymorphicobjs in your class is enough to create one. The vector will store its data elements on the heap anyway. You can call its constructor in your class's constructor's initialization list, if you want to. Otherwise it defaults to an empty vector.

To create new objects and put them in the vector:

polymorphicobjs.push_back(new B());

This will add a new B object to your vector.

You will need to delete them at some point (such as the destructor).

for (vector<A*>::iterator it = polymorphicobjs.begin(), end_it = polymorphicobjs.end(); it != end_it; ++it)
{
    delete *it;
}

A vector of smart pointers would be better..