简体   繁体   中英

Create a vector of sub classes?

I have been using a dynamic array but I had to add and remove items. I've read it's not recommended to use realloc or to resize the arrays when one can simply use std::vector however I'm having problems in changing my array to a vector.

This is my current code:

int main(){
    // This is what I'm doing now
    State*arr[3];
    int pos = 0;
    arr[0] = new Menu();
    // How do I change it to a vector? This is what I'm trying:
    std::vector<State> vec;
    vec.push_back(Menu());
    ...
}

However I keep getting error: "Cannot allocate an object of abstract type 'State'" What am I doing wrong?


These are class State and Menu:

class State
{
public:
    virtual ~State() {};
    virtual void capture_events() = 0;
    virtual void logic() = 0;
    virtual void render() = 0;
};

Menu : public State
{
public:
    Menu();
    ~Menu();
    void capture_events();
    void logic();
    void render();
};

You need extra indirection because State is a polymorphic base class. You can do this using std::unique_ptr from <memory> .

#include <memory>

std::vector<std::unique_ptr<State>> states;
states.emplace_back(new Menu());

It is very important to use std::unique_ptr<State> and not State* , because of exception safety. Consider the following:

std::vector<State*> states;
states.push_back(new Menu());
foo(); // what if foo throws an exception?
       // the next line wouldn’t get executed!
for (auto ptr : states) delete ptr;

In contrast, std::unique_ptr uses RAII to make sure the objects are always deleted if the vector goes out of scope, even in the case of early returns or exceptions. For further reference, see The Definitive C++ Book Guide and List .

You cannot instantiate a class which has pure virtual methods, ie a method like

virtual void func() = 0;

The =0 means that you must derive the class and implement this method there. This derived class can be instantiated.

As long as a class contains pure virtual methods you cannot instantiate it and you will get your error.

If you use a vector you objects must be default constructible. You can not construct a object of your class State if one of the virtual methods is marked with =0 to set the class abstract. The idea to have a abstract class is that you can't create objects of that class.

What you maybe want to do:

Create a class family with a abstract base like your State. Create a vector of pointers to instances( objects) of your class. Create the objects with new and push_back the pointer to your vector. If you erase some elements don't forget to delete the objects with delete.

Don't forget to make the destructor of your family also virtual!

Something like that:

class Base
{
     virtual void Do() =0;
     virtual ~Base();
};

class A: public Base
{
     void Do() { ... }
}

class B ...
class C ...

// Create your vector somewhere...
vector<Base*> myVect;


void AddObject()
{
    // It is not important which kind of object you create. Base* obj can "hold" every
    // object which is build from a class which is derived from Base!
    Base* obj=new A();
    myVect.push_back(obj); 
}

void DeleteObj( Base* obj )
{
    myVect.erase( ...find the object...);
    delete obj;
}

void PopBack()  
{
     Base* ptr = myVect.back(); // get last object pointer 
     delete ptr;                // delete the object
     myVect.pop_back();         // remove pointer to object from vector
}

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM