我有以下情况:
class A {
public:
int a;
// Just for RTTI
virtual ~A() = default;
}
class B : public A {
public:
int b;
}
然后创建一个std::unordered_map<int, A>
,在这里我希望能够同时存储A
和B
,然后回到它们的原始表示形式。
通过查看关键字,我总是知道在A
的位置上元素是对应于B
还是find()
。
但是,如果我运行以下程序:
#include <unordered_map>
#include <iostream>
using namespace std;
class A {
public:
int a{};
A() = default;
A(int a) : a(a){}
// Just for RTTI
virtual ~A() = default;
};
class B : public A {
public:
B(int a, int b) : A(a), b(b) {}
int b;
};
int main()
{
std::unordered_map<int, A> m;
m[1] = A(4);
m[2] = B(2,5);
if (dynamic_cast<B *>(&m.at(2)) == nullptr) {
std::cout << "FAIL!" << std::endl;
}
}
我的屏幕上显示“失败”。这不是我期望的行为;我该如何工作?
答案 0 :(得分:1)
您遇到的是object slicing -特别是您的hr_org_chart
只能包含类型A的对象。当您尝试将unordered_set<int, A>
类型的对象放入其中时,它会编译,但实际上只有B
对象的超类部分才被复制到数据结构中-子类部分(即部分不属于B
超类的B
对象中的一个对象被“分割”并丢弃,存储在集合中的只是另一个A
。
如果您希望A
包含不同子类的值,那么唯一的方法是通过某种指针间接存储值对象;例如,您可以改用unordered_set
,或者最好使用unordered_set<int, A*>
(这样可以防止内存泄漏)。然后,您需要先在堆上分配每个A / B对象,然后再将其插入到集中。
(另一种方法是为每个子类保留单独的unordered_set<int, shared_ptr<A> >
,例如,使用unordered_set
和 unordered_set<int, A>
。那会使您的呼叫代码复杂化
答案 1 :(得分:1)
以防万一将来有人遇到这种情况,您可以采取的另一种方法是使用std::variant
并保留单个哈希表,而不必-至少直接使用Jeremy建议的指针。