I\'m trying to make a vector in C++ that can store 3 different data types. I do not want to use the boost library. Something like:
vector
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. It cannot hold reference or array types, for example, 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 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;
I'm trying to make a vector in C++ that can store 3 different data types.
The answer here really depends on the particular use case:
If the objects are somehow connected and similar in some fashion - create a base class and derive all the classes from it, then make the vector store unique_ptr
s to the parent class (see ApproachingDarknessFish s answer for details),
If the objects are all of fundamental (so built-in) types - use an union
that groups the types and define a vector<yourUnionType>
,
If the objects are of unknown type, but you're sure they share a similiar interface, create a base class, and derive a templated child class from it (template <typename T> class container: public parent{};
), and create a vector<unique_ptr<parent>>
like in the first case,
If the objects are of types that for some reason cannot be connected (so for example the vector
stores int
, std::string
, and yourType
), connect them via an union
, like in 2. Or - even better...
...if you have time and want to learn something - look how boost::any
is implemented and try implementing it yourself, if you really don't want to use the library itself. It's not as hard as it may seem.
you could use std::any, store your objects in the vector as any and when you pull them out use type() == typeid(mytype)
https://en.cppreference.com/w/cpp/utility/any
This is only for C++17 onwards though.
Does it have to be a vector? You might just consider a linked list of generic type, then iterate through that list, use typeid() to figure out the data type of the node and pull the data with a node.get() function.