有很多方法可以解决具有不同成员的数据结构问题,而最好的方法很大程度上取决于它的使用方式。
最明显的是使用继承。您从基类中获得所有可能性:
struct base_struct {
int id;
std::string name;
};
list<base_struct*> some_list;
struct some_struct : public base_struct {
double metricA;
};
struct some_other_struct : public base_struct {
int metricB;
};
base_struct *s1 = new some_struct;
s1->id = 1;
// etc
base_struct *s2 = new some__other_struct;
s2->id = 2;
// etc
some_list.push_back(s1);
some_list.push_back(s2);
棘手的一点是,您必须确保当您取出元素时,您的大小写正确。 dynamic_cast
可以以类型安全的方式执行此操作:
some_struct* ss = dynamic_cast<some_struct*>(some_list.front());
您可以使用以下方式在投射之前查询名称type_info
:
typeid(*some_list.front()).name();
请注意,这两者都需要使用 RTTI 构建,这通常是可以的,但并非总是如此,因为 RTTI 会降低性能并且会增加内存占用,尤其是在广泛使用模板的情况下。
在之前的项目中,我们使用boost any处理过类似的事情。的优点any
是它允许您混合不是从彼此派生的类型。回想起来,我不确定我是否会再次这样做,因为它使代码在运行时有点太容易失败,因为类型检查被推迟到那时。(这种dynamic_cast
方法也是如此。
在糟糕的旧 C 时代,我们用 a 解决了同样的问题union
:
struct base_struct {
int id;
std::string name;
union { // metricA and metricB share memory and only one is ever valid
double metricA;
int metricB;
};
};
同样,您有一个问题,您必须自己处理确保它是正确的类型。
在 STL 之前的时代,许多容器系统被编写为采用void*
,再次要求用户知道何时进行转换。从理论上讲,您仍然可以通过说list<void*>
但您无法查询类型来做到这一点。
编辑:永远不要使用这种void*
方法!