c++ - 在 unordered_set 中存储多态对象

标签 c++ hash unordered-set

假设我有一个基类

struct Base {
    int x;
};

我知道有一个Derived派生自 Base 的类,但目前我无法获得它的定义(它存在于下游模块中)。

现在我有一个unordered_set<Base*>它将存储 Base 的混合物和Derived对象。如果我不指定自定义哈希函数,则此 unordered_set 是否可以正常工作(即按元素的实际类型对元素进行哈希,以便两个具有相同 Derived 但在其他派生字段中不同的 x 对象被视为不同)?

假设我确实需要一个自定义哈希函数,因为我没有 Derived 的定义然而,我希望将我的哈希函数编写为 Base 的虚拟成员函数这样Derivedunordered_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;

可能是一个更好的主意。

关于c++ - 在 unordered_set 中存储多态对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55895037/

相关文章:

c++ - 链接列表与 vector

c++ - 字段声明为 void/struct 或未在此范围内声明的变量

node.js - 如何在 Node js for payumoney 支付网关集成中创建哈希键?

java - 使用 hashmap 的空间复杂度。应该考虑 key 大小吗?

c++ - 如何在一组迭代器上调用 `find`,通过迭代器指向的内容进行查找?

c++ - 使用用户定义的文字对字符串进行编译时加密

c++ - 奇怪的声明(模板)。 C++

perl - 跨 Perl 脚本共享哈希

python - 有谁真的知道 Python 中集合的顺序是如何决定的?

C++ 严格弱排序派生类