storing two different class objects in a vector

2019-05-22 00:45发布

问题:

I'm trying to find a good way to store two different class objects within one vector each object having it's own location within the vector, so the objects can be stored and accessed later when needed.

I have used a structure but then I store everything which the structure has to the vector which isn't what I want, I'll give an example of what I mean.

Class A{
   public:
     void changeNumber(int x) {number = x;}
   private:
     int number;
};

Class B{
   public:
     void changeNumber(int x) {number = x;}
   private:
     int number;
};

struct Object{
   A a;
   B b;
};

Class Main{
   public:
     void storeObject(Object ob) {object.push_back(ob);}
   private:
     std::vector<Object> objects; //when an object is passed both A and B objects are stored within the vector in the same location
};

Is there a way where I can store two different class objects within one object but only pass one at a time to be stored so I has it's own index within the vector?

回答1:

If A and B have common functions and you'll be calling only these on the elements of a vector, you can take all common members and member functions and make a base class out of it. Then make A and B derived class of Object:

class Object
{
public:
    virtual ~Object() = default;

    void changeNumber(int x) { number = x; }

private:
    int number;
};

class A : public Object
{
    // extension of Object
};

class B : public Object
{
    // extension of Object
};

In this case, A is no different from B, so everything is implemented in Object.

Finally, your vector will look like this:

std::vector<Object*> objects;

And here's more preferred solution with std::shared_ptr which frees the memory for you after the element is removed from the vector or destructed otherwise.

std::vector<std::shared_ptr<Object>> objects;

Store object:

void storeObject(std::shared_ptr<Object> const& ob)
{
    objects.push_back(ob);
}

// Example calls
Main main;
main.storeObject(std::make_shared<Object>(A())); // store A
main.storeObject(new A()); // logically same as above

main.storeObject(std::make_shared<Object>(B())); // store B
main.storeObject(new B());

boost::variant is the way to go when storing multiple different types on which you cannot use inheritance.



回答2:

You can use boost::variant. It is type that can represent a finite set of types, in your example you would have an

std::vector<boost::variant<A,B> > objects;

An alternative (which does not really fit your usecase, but may for future readers) is boost::any. It can represent any type which is useful if you do not have a finite list of possible types at compile time.



回答3:

If you prefer to use your own "variant equivalent". You could do something along the lines of

struct Object{ 
    std::shared_ptr<A> a; 
    std::shared_ptr<B> b;
};

std::vector<Object> objects;

Object one; 
one.a = std::make_shared<A>();
objects.push_back(one);

Object two; 
two.b = std::make_shared<B>();
objects.push_back(two);

for(auto object: objects) {
     if(object.a) {
          object.a->changeNumber(1);
     } else if(object.b) {
          object.b->changeNumber(2);
     }
}

However, I still think that solving this with an appropriate inheritance scheme (as in the other answer) is much cleaner.



标签: c++ class vector