EDIT: as of C++17, the standard library now includes the class template std::variant, which is quite similar to pre-existing solutions in boost. variant
is a type-safe alternative to unions that allows multiple types to be joined using an “or” relationship, e.g., an std::variant<type1, type2, typ3>
contains either a type1
OR a type2
OR a type3.
It can be composed with std::vector
to yield exactly what you’ve described:
std::vector<std::variant<type1, type2, type3>> vectorName;
However, std::variant
does introduce some restrictions. For example, it cannot hold reference or array types, and the underlying type (i.e. type1
or type2
) can only be accessed by template code. If std::variant
does not permit the specific behavior you need, keep reading for a more complicated but more versatile approach that also has the benefit of working in any version of C++.
ORIGINAL ANSWER:
The easiest way to store multiple types in the same vector is to make them subtypes of a parent class, wrapping your desired types in classes if they aren’t classes already.
class Parent {
// Anything common to the types should be declared here, for instance:
void print() { // Make this virtual if you want subclasses to override it
std::cout << "Printing!";
}
virtual ~Parent(); //virtual destructor to ensure our subclasses are correctly deallocated
};
class Type1 : public Parent {
void type1method();
};
class Type2 : public Parent {
void type2Method();
};
class Type3 : public Parent {
void type3Method();
};
You can then create a vector of Parent
pointers that can store pointers to the child types:
std::vector<Parent*> vec;
vec.push_back(new Type1);
vec.push_back(new Type2);
vec.push_back(new Type3);
When accessing elements directly from the vector, you’ll only be able to use members that belong to Parent
. For instance, you can write:
vec[0]->print();
But not:
vec[0]->type1Method();
As the element type has been declared as Parent*
and the Parent
type has no member named type1Method
.
If you need to access the subtype-specific members, you can convert the Parent
pointers to subtype pointers like so:
Parent *p = vec[0];
Type1 *t1 = nullptr;
Type2 *t2 = nullptr;
Type3 *t3 = nullptr;
if (t1 = dynamic_cast<Type1*>(p)) {
t1->type1Method();
}
else if (t2 = dynamic_cast<Type2*>(p)) {
t2->type2Method();
}
else if (t3 = dynamic_cast<Type3*>(p)) {
t3->type3Method();
}
Although it’s generally considered a better idea to avoid this kind of explicit type-branching and instead rely on virtual methods.
Be sure to delete the pointers before removing them from the vector if you use dynamic allocation, as I did in the example above. Alternatively, use smart pointers (probably std::unique_ptr
) and let your memory take care of itself:
std::vector<std::unique_ptr<Parent>> vec;