c++ - 在 unordered_set 中存储多态对象
问题描述
说我有一个基类
struct Base {
int x;
};
而且我知道有一个Derived
派生自 的类Base
,但此时我无法获得它的定义(它存在于下游模块中)。
现在我有一个unordered_set<Base*>
将存储Base
和Derived
对象的混合物。如果我不指定自定义散列函数,这个 unordered_set 是否可以正常工作(即按元素的实际类型散列元素,以便在其他一些派生字段中Derived
具有相同x
但不同的两个对象被视为不同)?
假设我确实需要一个自定义散列函数,因为我还没有定义Derived
,我希望将我的散列函数编写为的虚拟成员函数,Base
以便可以简单地覆盖该函数以在调用Derived
时执行自己的散列unordered_set
它。这可能吗?或者对于此类问题是否有其他首选/既定解决方案?
解决方案
是的,你可以这样做:
#include <iostream>
#include <functional>
#include <unordered_set>
#include <memory>
struct Base {
int x;
virtual size_t hash() const {
return std::hash<int>()(x);
}
};
// just some Derived example
struct Derived : Base {
int y;
// performing hashing for a pair of integers
virtual size_t hash() const override {
return std::hash<int>()(x) ^ std::hash<int>()(y);
}
};
struct Hasher {
size_t operator()(const Base* ptr) const {
return ptr->hash();
}
};
struct CheckEq {
bool operator()(Base* lhs, Base* rhs) const {
auto dLhs = dynamic_cast<Derived*>(lhs);
auto dRhs = dynamic_cast<Derived*>(rhs);
// different types
if ((dLhs == nullptr) != (dRhs == nullptr)) {
return false;
}
// both Base
if (dLhs == nullptr && dRhs == nullptr) {
return lhs->x == rhs->x;
}
// both Derived
return dLhs->x == dRhs->x && dLhs->y == dRhs->y;
}
};
int main() {
std::unordered_set<
Base*,
Hasher, // struct with defined size_t operator()(const Base*) const, returning hash of object
CheckEq // struct with defined bool operator(const Base*, const Base*) const for additional checking whether 2 objects with same hashes are different
> set;
// checking if it works
auto objBase1 = std::make_unique<Base>();
objBase1->x = 5;
auto objBase2 = std::make_unique<Base>();
objBase2->x = 5;
auto objBase3 = std::make_unique<Base>();
objBase3->x = 6;
auto objDerived1 = std::make_unique<Derived>();
objDerived1->x = 5;
objDerived1->y = 6;
auto objDerived2 = std::make_unique<Derived>();
objDerived1->x = 5;
objDerived1->y = 6;
auto objDerived3 = std::make_unique<Derived>();
objDerived1->x = 50;
objDerived1->y = 60;
set.insert(objBase1.get());
set.insert(objBase2.get());
set.insert(objBase3.get());
set.insert(objDerived1.get());
set.insert(objDerived2.get());
set.insert(objDerived3.get());
std::cout << set.size() << std::endl; // prints 4
return 0;
}
UPD。在我看来,您需要将对象存储在某个地方,所以
std::unordered_set<
std::unique_ptr<Base>, // or shared_ptr
Hasher,
CheckEq
> set;
可能是一个更好的主意。
推荐阅读
- qt - 为什么在 QQuickWidget 上给出 id 时 QML 菜单不会在外部按下时关闭?
- javascript - 为什么我的动作在传递给事件处理程序时没有调度
- r - 使用重叠阈值逐行选择跨列组合
- javascript - Redux action 和 async/await 函数在类组件和函数中具有不同的行为
- heroku - 此响应无法在 Heroku 中设置 Cookie
- python - 如何在不同的“框架”之间切换
- python - Discord.py 使用 webhook 向特定公会发送消息
- python - 检查泡菜转储的依赖关系
- unity3d - 使用没有 Canvas 的输入字段,或找到任何替代方法
- linux - 从列表中选择文件