2017-09-24 48 views
0

如何为派生类创建高效的equals方法?如何对派生类进行平等测试

struct Base { 
    virtual bool equals(const Base &other) const = 0; 
}; 

通常的答案是使用dynamic_casttypeid在派生类中,检查标识类型,如果类型匹配,然后做一个比较:

struct Derived: Base { 
    virtual bool equals(const Base &other) const override { 
     if (typeid(*this)!=typeid(other)) return false; 

     return *this==static_cast<Derived &>(other); 
    } 
}; 

有没有更有效的方法来做到这一点类型检查?如果我们禁用了RTTI,我们可以做些什么?

+0

如果您愿意违背Liskov替代原则(这样做会引入可能会或可能不会被您接受的其他折衷),请使用双派遣。 – Peter

+0

@Peter:你的意思是一个解决方案,所有派生类型都需要以某种形式列出? – geza

+0

好吧,是的。如果你想要的行为取决于类型,而不需要测试类型(或类型ID),就必须针对每个重要的类型做一些特定的事情。 – Peter

回答

0

我从来没有见过这种“猫腻”,所以我将其添加在这里:

struct Base { 
    virtual bool equals(const Base &other) const = 0; 

    virtual const void *typeMarker() const = 0; 
}; 

struct Derived: public Base { 
    static char s_typeMarker; 

    virtual bool equals(const Base &other) const override { 
     if (&s_typeMarker!=other.typeMarker()) return false; 

     return *this==static_cast<Derived &>(other); 
    } 

    virtual const void *typeMarker() const override { 
     return &s_typeMarker; 
    } 
}; 

基本上,它有一个typeMarker()虚函数,该函数返回为每种类型的唯一值。因此,类型检查使用虚拟函数调用(和比较)完成,该函数可能比typeiddynamic_cast便宜,并且此方法在禁用RTTI的情况下可以工作。

我知道的唯一缺点是这可能无法正确跨越.dlls工作。

(基于这个答案,也许有人能想出更好的解决方案。)

1

我觉得最核心的问题是,你不应该需要比较的类型。这需要总是表现出糟糕的设计,不正确的继承使用或其他不良模式。

看看你为什么需要平等信息 - 你打算怎么处理它下一个你不能通过调用一个被覆盖和重写的类的方法来做到这一点吗?

+0

一般来说,我同意你的看法。但是,在某些情况下,这种功能很有用。例如,按值从容器中移除元素。对于没有'operator =='的类型,这只能用某种类型的标记来实现(add会返回一个可以在remove处使用的标记)。 – geza

+0

当你想要实现组播功能时,出现这个问题[Herb Sutter谈到这个问题](http://www.drdobbs.com/cpp/generalizing-observer/184403873)。不幸的是,事实证明,当前的C++ lamba's不能相互比较,所以在不使用令牌的情况下,不能用当前的C++来完成。 – geza