类层次结构的哈希表

时间:2019-01-14 04:37:57

标签: c++ unordered-map

我有以下情况:

class A {
public:
 int a;

 // Just for RTTI
 virtual ~A() = default;
}

class B : public A {
public:
 int b;
}

然后创建一个std::unordered_map<int, A>,在这里我希望能够同时存储AB,然后回到它们的原始表示形式。

通过查看关键字,我总是知道在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;
    }
}

我的屏幕上显示“失败”。这不是我期望的行为;我该如何工作?

2 个答案:

答案 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建议的指针。