2010-09-18 131 views
6

我有一個基類實現基類比較的正確方法是什麼?

class Animal 

與純虛函數,和一組派生類

class Monkey : public Animal 
class Snake : public Animal 

我想實現一個比較操作的,這樣,如果我遇到兩個指針動物在我的代碼

Animal* animal1 
Animal* animal2 

我可以將它們相互比較。如果animal1和animal2具有不同的派生類,則比較應該產生錯誤。如果它們具有相同的派生類,則應返回比較運算符的輸出。

有人可以指出我實現這個好方法嗎?

回答

4

哇,很多其他的答案是完全沒有必要的。 dynamic_cast-它存在,使用它。

class Animal { 
public: 
    virtual bool operator==(const Animal& other) = 0; 
    virtual ~Animal() = 0; 
}; 
template<class T> class AnimalComp : public Animal { 
public: 
    virtual bool operator==(const Animal& ref) const { 
     if (const T* self = dynamic_cast<const T*>(&ref)) { 
      return ((T*)this)->operator==(*self); 
     } 
     return false; 
    } 
    virtual bool operator!=(const Animal& ref) const { 
     if (const T* self = dynamic_cast<const T*>(&ref)) { 
      return ((T*)this)->operator!=(*self); 
     } 
     return true; 
    } 
}; 
class Monkey : public AnimalComp<Monkey> { 
public: 
    virtual bool operator==(const Monkey& other) const { 
     return false; 
    } 
    virtual bool operator!=(const Monkey& other) const { 
     return false; 
    } 
}; 
class Snake : public AnimalComp<Snake> { 
public: 
    virtual bool operator==(const Snake& other) const { 
     return false; 
    } 
    virtual bool operator!=(const Snake& other) const { 
     return false; 
    } 
}; 

編輯:在我的自動模板實現前鞠躬!

編輯編輯:我做的一件事是忘記標記爲const,這是我的錯誤。我不會爲沒有做而道歉!=因爲,讓我們面對它,實施它是一個總的輕而易舉的事情。

更多編輯:耶穌基督傢伙,這不是如何寫!=或==的例子,這是一個如何使用CRTP的例子。如果你不喜歡我選擇實施我的!=或==,你可以起訴。

+0

是的,與運營商==超載更好。 – imaginaryboy 2010-09-18 22:09:41

+0

雖然小錯誤,需要是'const monkey * p = dynamic_cast (&other)'和'return * this == * p' ...引用不能轉換爲'bool'。 – imaginaryboy 2010-09-18 22:22:35

+0

@imaginaryboy:是的,我解決了一個更好的解決方案。 – Puppy 2010-09-18 22:28:24

3

由於沒有與兩個指針相關的靜態類型信息,因此您需要使用RTTI。您可以比較類型typeid operator的結果以確定對象是否屬於同一類型。

另一種方法是將您自己的類型ID添加到Animal類。添加另一個虛函數並派生類返回唯一標識類型的內容。您可以使用枚舉,或者可以使用字符串的名稱。如果你可以使用它,但是,RTTI會好得多恕我直言。

+0

+1。另外--RTTI會產生一些運行時開銷(顯然),儘管不會太多。如果你的應用程序有大量的類,並且你只需要在幾個地方使用RTTI,那麼我會用專門的類型識別功能來解決你自己的解決方案。但是,如果RTTI的使用很普遍,那麼您應該使用自己的方法來使用它。 – 2010-09-18 19:42:45

+1

我認爲雙重調度可能是一個更好的方法來做到這一點比手動擺弄'std :: type_info'對象。無論如何,一旦你知道這是正確的類型,你會怎麼做?您仍然必須將指針轉換爲派生類的指針。由於C++僅運行最小的RTTI,因此您可能不得不切換類型。而一種類型的切換通常強烈表明有人最好使用「虛擬」功能。 – sbi 2010-09-18 20:08:10

+0

@sbi約定,實際上。我花了太多時間勉強編程「The Java Way」(tm)。它顯然影響了我的C++。 – 2010-09-18 20:13:18

4

的一種方法,是使用雙調度「同一類」和「不同類」之間的區別:

class Monkey; 
class Snake; 

class Animal { 
public: 
    virtual bool compare_impl(const Animal*) const { return false; } 
    virtual bool compare_impl(const Monkey*) const { return false; } 
    virtual bool compare_impl(const Snake*) const { return false; } 
    virtual bool compare(const Animal* rhs) const =0; 
}; 

class Monkey : public Animal { 
private: 
    /* Override the default behaviour for two Monkeys */ 
    virtual bool compare_impl(const Monkey*) const { /* compare two Monkey's */ } 
public: 
    /* Let overload-resolution pick the compare_impl for Monkey and let virtual dispatch select the override in the dynamic type of rhs */ 
    virtual bool compare(const Animal* rhs) const { return rhs->compare_impl(this); } 
}; 

class Snake : public Animal { 
private: 
    /* Override the default behaviour for two Snakes */ 
    bool compare_impl(const Snake*) const { /* compare two Snakes */ } 
public: 
    /* Let overload-resolution pick the compare_impl for Monkey and let virtual dispatch select the override in the dynamic type of rhs */ 
    virtual bool compare(const Animal* rhs) const { return rhs->compare_impl(this); } 
}; 
+0

你能解釋一下使用Animal :: compare_impl的行嗎?手段?到目前爲止,我只在「using namespace foo」中看到關鍵字「using」。 – Hans 2010-09-18 20:01:30

+0

@Hans:它將一個基類的標識符帶入派生類的範圍,防止派生類重載隱藏基類函數。 – sbi 2010-09-18 20:05:07

+0

他的'使用'聲明做了兩件事:1)改變基類'compare_impl'從受保護到私有的訪問,2)使Animal :: compare_impl可訪問,因爲它被派生類的'compare_impl'聲明隱藏。 – imaginaryboy 2010-09-18 20:16:28

0

這裏有一個小竅門我使用(我希望它也能爲你工作)。 我下面的私有方法添加到動物並在每一個派生類中重寫它(我知道,它是有點麻煩,但它比RTTI更快)

class Animal { 
protected: 

virtual const void* signature() const 
{ 
    static bool dummy; 
    return &dummy; 
} 
... 
} 


class Monkey : public Animal { 
private: 
virtual const void* signature() const 
{ 
    static bool dummy; 
    return &dummy; 
} 
... 
} 

現在爲了看兩個指針( a和b)是同一類的只是檢查

A->簽名()== B->簽名()

它不是一個真正的解決方案,這是一個把戲,但它只有2個工作虛擬方法調用(每個指針爲1),因此速度很快。

相關問題