class 层次结构的哈希值 table
Hash table of class hierarchy
我有以下情况:
class A {
public:
int a;
// Just for RTTI
virtual ~A() = default;
}
class B : public A {
public:
int b;
}
然后我创建了一个 std::unordered_map<int, A>
,我希望能够在其中存储 A
s 和 B
s,并返回到它们的原始表示形式。
我总是知道该元素是对应于 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;
}
}
我的屏幕上打印了 "FAIL"。这不是我期望的行为;我怎样才能让它工作?
您 运行 进入的是 object slicing -- 特别是,您的 unordered_set<int, A>
只能包含类型 A 的对象。当您尝试将 B
类型的对象放入其中时,它会编译,但实际上只有 B
对象的超类部分被复制到数据结构中——子类部分(即部分不属于 A
超类的 B
对象)被 "sliced off" 丢弃,存储在集合中的只是另一个 A
.
如果您希望 unordered_set
包含不同子类的值,那么唯一的方法是通过某种指针间接存储值对象;例如,您可以改用 unordered_set<int, A*>
,或者更好的是 unordered_set<int, shared_ptr<A> >
(这样您就可以避免内存泄漏)。然后,您需要在堆上分配每个 A/B 对象,然后再将其插入集合中。
(另一种方法是为每个子类保留一个单独的 unordered_set
,例如有一个 unordered_set<int, A>
和 一个 unordered_set<int, B>
。当然,这样做的缺点是它会使您的调用代码复杂化)
以防万一将来有人遇到这个问题,您可以采取的另一条路是使用 std::variant
并保留单个散列 table 而不是 - 至少直接 - 使用 Jeremy 建议的指针.
我有以下情况:
class A {
public:
int a;
// Just for RTTI
virtual ~A() = default;
}
class B : public A {
public:
int b;
}
然后我创建了一个 std::unordered_map<int, A>
,我希望能够在其中存储 A
s 和 B
s,并返回到它们的原始表示形式。
我总是知道该元素是对应于 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;
}
}
我的屏幕上打印了 "FAIL"。这不是我期望的行为;我怎样才能让它工作?
您 运行 进入的是 object slicing -- 特别是,您的 unordered_set<int, A>
只能包含类型 A 的对象。当您尝试将 B
类型的对象放入其中时,它会编译,但实际上只有 B
对象的超类部分被复制到数据结构中——子类部分(即部分不属于 A
超类的 B
对象)被 "sliced off" 丢弃,存储在集合中的只是另一个 A
.
如果您希望 unordered_set
包含不同子类的值,那么唯一的方法是通过某种指针间接存储值对象;例如,您可以改用 unordered_set<int, A*>
,或者更好的是 unordered_set<int, shared_ptr<A> >
(这样您就可以避免内存泄漏)。然后,您需要在堆上分配每个 A/B 对象,然后再将其插入集合中。
(另一种方法是为每个子类保留一个单独的 unordered_set
,例如有一个 unordered_set<int, A>
和 一个 unordered_set<int, B>
。当然,这样做的缺点是它会使您的调用代码复杂化)
以防万一将来有人遇到这个问题,您可以采取的另一条路是使用 std::variant
并保留单个散列 table 而不是 - 至少直接 - 使用 Jeremy 建议的指针.