类和子类的通用哈希函数

时间:2010-11-20 18:00:28

标签: c++ class hash hashtable hierarchy

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

class A {
    int a;
};

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

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

我需要能够通过散列函数运行BC来获取对象的散列。

我应该怎么做?我只想做sizeof(thing)并对原始字节进行哈希处理,但这是一个很好的方法吗?我还想过在基类中有virtual uint_32 hash() = 0,但是对于每个子类都必须实现它是不是最理想的。

2 个答案:

答案 0 :(得分:2)

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

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

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

C的情况特别棘手:如果两个C对象指向不同的otherClass对象,但两个otherClass对象相等,那么两个C对象是否应该具有相同的哈希值?你无法完全概括地定义它,它是C类的属性。

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

答案 1 :(得分:1)

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

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

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

我建议从2开始,然后转到3个零碎。