Making a vector of instances of different subclasses

跟風遠走 提交于 2019-11-28 00:16:38

Yes, but you'll need to use either pointers or smart pointers (I'd go with this).

struct X
{
    virtual ~X() {}  //<--- as pointed out in the comments
                     // a virtual destructor is required
                     // for correct deletion
    virtual void foo() = 0;
};
struct Y : X
{
    virtual void foo() { }
};

int main()
{
    std::vector<X*> a;
    a.push_back(new Y);
    a[0]->foo();
    for ( int i = 0 ; i < a.size() ; i++ )
        delete a[i];
    return 0;
}

Don't forget to delete the allocated memory.

Why you can't use actual objects:

Assume std::vector<X>. This is illegal because:

  1. If you want to initialize your vector with some number of elements, the allocation would fail. A vector stores objects internally in continuous memory. A preallocation would fail because it would mean it needed to create objects, which can't be done for abstract classes.

  2. Even if you could, or the base class wasn't abstract, it wouldn't help too much, as you'd suffer from object slicing.

Since each of those objects is different sizes, the proper way to do this is a container containing pointers to the base class Unit, (and be sure it has a virtual destructor.

Option 1: boost::ptr_vector (requires boost libraries, which you should have anyway)

ptr_vector<Unit> units;
units.push_back(new Soldier());

Option 2: std::vector<std::unique_ptr<Unit>> (requires C++11 compiler)

std::vector<std::unique_ptr<Unit>> units;
units.emplace_back(std::unique_ptr<Unit>(new Soldier()));

You cannot literally create a vector of objects of an abstract class, because the vector template needs to be able to tell the compiler, at compile time, the size of its element. However, you can get what you want by keeping a vector of pointers to objects rather than a vector of objects as such.

Update: Abstract classes as such have known size. It is actually instances of their most derived types whose sizes are unknown at compile time. (Thanks @LuchianGrigore and @MooingDuck for pointing this out.)

paulrehkugler

I don't think it's possible to do this:

std::vector<Unit> unit_list;
unit_list.push_back(Soldier(params));

Because Soldier, Vehicle, and Unit take up different amounts of memory.

However, it might be possible to use pointers, as all pointers take up a fixed amount of memory:

std::vector<Unit*> unit_list;
unit_list.push_back(new Soldier(params));

I haven't tested it, but it makes sense in my head anyway.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!