Objects of Different Classes in a Single Vector

Objects of different classes in a single vector?

Sphere and Plane would need a common base type, or your vector would need to be composed of void*'s.

Common base type (better):

class Shape { ... };
class Sphere : public Shape { ... };
class Plane : public Shape { ... };

std::vector<Shape*> shapes;

or void*'s (not great):

std::vector<void*> shapes;

How to store different class objects in a single array/vector?

vector <A*> mainvec = { vecb, vecc, vecd, vece };

This can never work. mainvec expects to hold raw A* pointers, but you are trying to pass it vectors of objects instead.

If you really want a vector to hold other types of vectors, you could use std::variant for that, eg:

std::vector<B> vecb;
std::vector<C> vecc;
std::vector<D> vecd;
std::vector<E> vece;

using VariantOfVectors = std::variant< std::vector<B>*, std::vector<C>*, std::vector<D>*, std::vector<E>* >;

std::vector<VariantOfVectors> mainvec = { &vecb, &vecc, &vecd, &vece };

How do I store different classes in a single vector?

You have to store pointers (Framework*), or std::shared_ptr< Framework > (possibly std::unique_ptr< Framework >) instances. That allows to use virtual calls and late binding - meaning that when you refer to your objects, the right function to call will be determined at runtime. Don't forget to make your functions virtual

Then, your code (in similar fashion)

for (vector< Framework* >::iterator num = gameObjects.begin(); num != gameObjects.end(); ++num)
{
Framework* currentObject = *num;
currentObject->frameEvent();
currentObject->frameEndEvent();
currentObject->DrawEvent();
}

However, I'd recommend sth like this (c++11 required)

vector< std::unique_ptr< Framework > > gameObjects;

...

for (auto & currentObject : gameObjects)
{
currentObject->frameEvent();
currentObject->frameEndEvent();
currentObject->DrawEvent();
}

Last one (range for loop) should work regardless of the type used (you may use normal pointer or shared_ptr or unique_ptr as example shows).

If you are interested in using unique_ptr, please note that in order to store these on std::vector, you have to use std::move, as there can only be one instance of std::unique_ptr (as name suggests). Consult this answer in case of problems.

storing two different class objects in a vector

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.

Printing variables of different derived class objects inside a single vector

One of the possible solutions is using virtual functions like in the following example. Take a look for the Print() methods below...

class Item
{
public:
int id;
Item(int id) { this->id = id; }
virtual void Print(std::ostream& os) { os << id << " "; }
};

class ItemTypeA : public Item
{
public:
int a;
ItemTypeA(int a, int id) : Item(id) { this->a = a; }
void Print(std::ostream& os) override { Item::Print( os ); os << a << std::endl; }
};

class ItemTypeB : public Item
{
public:
int b;
ItemTypeB(int b, int id) : Item(id) { this->b = b; }
void Print(std::ostream& os) override { Item::Print( os ); os << b << std::endl; }
};

int main()
{
std::vector<std::shared_ptr<Item>> items;
items.push_back(std::make_unique<ItemTypeA>(2, 0));
items.push_back(std::make_unique<ItemTypeB>(3, 1));

for ( auto& el: items ) { el->Print(std::cout); }
}

A vector for different classes

Here is an example that tries to stay as close to your example as it can using a template parameter on class storage_class. See working version here. I've added only option1 and made the member my_store public as you access it in your main function.

#include <memory>
#include <vector>
#include <iostream>

struct option1{
void create_data(){ std::cout << "created\n"; }
};

template<typename T>
class storage_class
{
public:
storage_class(int n)
{
for(int i = 0; i < n; i++)
my_store.push_back(std::make_unique<T>());
}

std::vector<std::unique_ptr<T>> my_store;
};

int main()
{
storage_class<option1> store(4);

int n_iterations = 4;

for(int i = 0; i < n_iterations; i++)
{
store.my_store[i]->create_data();
}
}

another option would be to use std::variant. See workign version here.

#include <memory>
#include <vector>
#include <variant>
#include <iostream>

struct option1{
void create_data(){ std::cout << "created 1\n"; }
};

struct option2{
void create_data(){ std::cout << "created 2\n"; }
};

class storage_class
{
public:

using option = std::variant<std::unique_ptr<option1>,std::unique_ptr<option2>>;

storage_class(int sel, int n)
{
if(sel == 0)
for(int i = 0; i < n; i++)
my_store.push_back(option(std::make_unique<option1>()));
else if(sel == 1)
for(int i = 0; i < n; i++)
my_store.push_back(option(std::make_unique<option2>()));
}

std::vector<option> my_store;
};

int main()
{
storage_class store(1, 4);

int n_iterations = 4;

for(int i = 0; i < n_iterations; i++)
{
std::get<1>(store.my_store[i])->create_data();
}
}

Vector of objects from different classes

Option 1 cannot work because obs is a vector<observable*>^. You cannot push a object of type observable because you can only store pointers (observable*) in it. You could store such objects in a vector<observable> but you cannot store Energy objects in such vector.

Option 2 cannot work because ecause obs is a vector<observable*>^. You cannot push a object of type std::shared_ptr<observable> because you can only store raw pointers (observable*) in it. To store shared pointers, the vector must be of type vector<shared_ptr<observable>>.

Option 3 is effectively same as option 4. They would work if you actually tried to push into the member variable obj. However, you've hidden that variable by declaring a local variable by the same name (the function parameter). You cannot push observable* into a vector of strings. The compilation error should be clear about this. If you inteded to push into the member variable, you can use this->obs instead, or even better, use different name for the local variable.

^Assuming you were actually pushing into this->obs rather than the local variable.

How to create a vector of objects which inherit from the same base classes and have unique functions?

I'm afraid what you want to achieve is not possible in a simple way. That is because the C++ mechanisms you are trying to use were not designed to be used in such a way.

Inheritance - you would use it if:

  • you want to reuse the interface, which seems not to be the case here, because you want different function names;
  • or, you'd want to reuse the implementation, aka common code which is already present in the base class.

In order to workaround your problem with different parameters, you could encapsulate those into a wrapper object, which can be created either from the first or the second set. Something like this:

class Input {
public:
Input(int angle_x, int angle_y, int P_scene, int V_scene, int M_scene);
Input(int P_scene, int V_scene, int M_scene);
...
};

class Model {
public:
virtual void draw(const Input& in);
...
};

class Bus: public Model {
public:
void draw(const Input& in) override;
...
};

class Grass: public Model {
public:
void draw(const Input& in) override;
...
};

int main() {
std::vector<Model*> models;
...
models[0]->draw(Input(angle_x, angle_y, P_scene, V_scene, M_scene));
models[1]->draw(Input(P_scene, V_scene, M_scene));
}


Related Topics



Leave a reply



Submit