Vector that can have 3 different data types C++

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;

Leave a Comment