可以有 3 种不同数据类型的向量 C++

2022-01-24 00:00:00 polymorphism vector c++

我正在尝试用 C++ 创建一个可以存储 3 种不同数据类型的向量.我不想使用 boost 库.比如:

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<type1, type2, type3> vectorName; 

我需要制作模板吗?如果是,我该怎么做?

Do I need to make a template? And if yes how would I do that?

推荐答案

从 C++17 开始,标准库现在包含类模板 std::variant,这与 boost 中预先存在的解决方案非常相似.variant 是联合的类型安全替代方案,它允许使用或"连接多个类型.关系,例如,std::variant 包含 type1type2type3. 它可以与 std::vector 组合以产生您所描述的内容:

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; 

但是,std::variant 确实引入了一些限制.例如,它不能保存引用或数组类型,并且底层类型(即 type1type2)只能通过模板代码访问.如果 std::variant 不允许您需要的特定行为,请继续阅读以了解更复杂但更通用的方法,该方法还具有在任何版本的 C++ 中工作的好处.

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++.

原始答案:

在同一个向量中存储多个类型的最简单方法是使它们成为父类的子类型,如果它们还不是类,则将所需的类型包装在类中.

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();
};

然后您可以创建一个 Parent 指针向量,它可以存储指向子类型的指针:

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);

当直接从向量访问元素时,您将只能使用属于 Parent 的成员.例如,你可以写:

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();

但不是:

vec[0]->type1Method();

由于元素类型已被声明为 Parent* 并且 Parent 类型没有名为 type1Method 的成员.

As the element type has been declared as Parent* and the Parent type has no member named type1Method.

如果您需要访问特定于子类型的成员,可以将 Parent 指针转换为子类型指针,如下所示:

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.

如果您使用动态分配,请务必在从向量中删除指针之前删除指针,就像我在上面的示例中所做的那样.或者,使用智能指针(可能是 std::unique_ptr)并让您的内存自行处理:

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;

相关文章