2017-09-24 37 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