【问题标题】:General purpose hashing function for classes and subclasses类和子类的通用散列函数
【发布时间】:2011-05-13 03:49:23
【问题描述】:

我正在编写一种类框架,我需要在其中获取对象的哈希值,以便将它们存储在哈希表中。
所以如果我有:

class A {
    int a;
};

class B : public A {
    const char* str;
};

class C : public A {
    double d;
    otherClass* oc;
};

我需要能够通过散列函数运行B's 或C's 以获得对象的散列。

我应该怎么做?我想过简单地做sizeof(thing) 并对原始字节进行散列,但这是一个好方法吗?我也想过在基类中包含virtual uint_32 hash() = 0,但是必须为每个子类实现它是次优的。

【问题讨论】:

    标签: c++ class hash hashtable hierarchy


    【解决方案1】:

    通常,您需要哈希函数与类中定义的相等性保持一致。也许相等是由重载的operator== 定义的,但即使没有重载,您也可能认为两个对象应该被视为相等,并且如果它们的所有数据成员都相等,则它们具有相同的哈希码。

    散列原始字节通常不起作用。不能保证数据成员都相等的两个对象将具有相等的字节。例如,出于对齐原因,对象中的某处可能存在一些填充,并且填充字节可以采用任何值。

    更糟糕的是,不能保证两个相等的 double 值具有相等的字节。例如,正/负零比较相等。

    C 的情况特别棘手:如果两个 C 对象指向不同的 otherClass 对象,但两个 otherClass 对象相等,那么这两个 C 对象应该具有相同的哈希值吗?您不能完全笼统地定义它,它是 C 类的属性。

    如果它也是可能的最好的东西,它会是“次优的”吗? ;-) 唯一通用的解决方案是定义一个函数hash,并为每个类编写一个版本。在您的情况下,您可以将其设为 A 的虚函数,但您也可以查看 std::hash 在 C++0x 中的工作方式:它实际上是一个模板仿函数类而不是一个函数,它可以专门用于用户定义类。当然,这不提供动态多态性,但是如果您将其专门用于A,并让实现调用您在每个类中实现的虚函数,那么您的散列函数将与std::unordered_map 等一起使用。

    【讨论】:

      【解决方案2】:

      如果对象具有未初始化的字段(对象具有不同的无意义位)或动态成员(对象具有不同的指针,即使它们指向相同的指针,执行 sizeof 的事情可以为您提供相同对象的不同哈希值数据)。最好的办法就是编写一个序列化程序,然后通过散列函数运行结果。

      至于为每个基类实现hash() 的成本,您有三个选择。

      1. 为基类实现“hash()”,但不要在所有派生类中重载它。派生类的某些对象将具有相同的哈希,即使它们不同。
      2. 使其成为纯虚拟(`virtual uint32 hash()=0`),在所有派生类中实现它,即使它有时是微不足道的(`hash() {return(0)}`)。与 1 相同的问题,但问题更容易看到。
      3. 咬紧牙关。为所有子类正确实现它。

      我建议从 2 开始,然后逐步过渡到 3。

      【讨论】:

        猜你喜欢
        • 2014-09-16
        • 1970-01-01
        • 2012-11-10
        • 1970-01-01
        • 1970-01-01
        • 2021-09-30
        • 1970-01-01
        • 2010-11-11
        • 2013-12-28
        相关资源
        最近更新 更多