我正在尝试在C ++中创建一个可以存储3种不同数据类型的向量。我不想使用boost库。 类似的东西:
vector<type1, type2, type3> vectorName;
我需要制作模板吗?如果是,我该怎么做?
答案 0 :(得分:11)
在同一向量中存储多个类型的最简单方法是使它们成为父类的子类型,如果它们不是类,则将所需类型包装在类中。
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
指针向量,可以存储指向子类型的指针:
std::vector<Parent*> vec;
vec.push_back(new Type1);
vec.push_back(new Type2);
vec.push_back(new Type3);
直接从向量访问元素时,您只能使用属于Parent
的成员。例如,您可以写:
vec[0]->print();
但不是:
vec[0]->type1Method();
由于元素类型已声明为Parent*
且Parent
类型没有type1Method
。
如果需要访问特定于子类型的成员,可以将Parent
指针转换为子类型指针,如下所示:
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();
}
虽然通常认为避免这种显式类型分支更好的想法,而是依赖虚拟方法。
如果使用动态分配,请确保在从向量中删除指针之前删除指针,就像我在上面的示例中所做的那样。或者,使用智能指针(可能是std::unique_ptr
)并让你的记忆自己处理:
std::vector<std::unique_ptr<Parent>> vec;
答案 1 :(得分:7)
我试图在C ++中创建一个可存储3种不同数据类型的向量。
这里的答案实际上取决于具体的用例:
如果对象以某种方式以某种方式连接和相似 - 创建基类并从中派生所有类,然后将向量存储unique_ptr
添加到父类(请参阅接近DarknessFish 的答案以获取详细信息),
如果对象都是基本(内置)类型 - 请使用union
对类型进行分组并定义vector<yourUnionType>
,
如果对象属于未知类型,但您确定它们共享一个类似的接口,则创建一个基类,并从中派生一个模板化的子类(template <typename T> class container: public parent{};
),然后创建第一种情况中的vector<unique_ptr<parent>>
,
如果对象属于由于某种原因无法连接的类型(例如vector
存储int
,std::string
和yourType
),通过union
连接它们,就像在 2 中一样。或者 - 甚至更好......
...如果你有时间并且想要学习一些东西 - 看看boost::any
是如何实现的,并尝试自己实现它,如果你真的不想使用它本身。它并不像看起来那么难。
答案 2 :(得分:1)
您可以使用std :: any,将您的对象以任何方式存储在向量中,当您将它们拉出时,请使用type()== typeid(mytype)
https://en.cppreference.com/w/cpp/utility/any
但这仅适用于C ++ 17起。
答案 3 :(得分:0)
它必须是矢量吗?您可能只考虑泛型类型的链表,然后遍历该列表,使用typeid()来计算节点的数据类型,并使用node.get()函数提取数据。