实现基类比较的正确方法是什么?

问题描述:

我有一个基类实现基类比较的正确方法是什么?

class Animal 

与纯虚函数,和一组派生类

class Monkey : public Animal 
class Snake : public Animal 

我想实现一个比较操作的,这样,如果我遇到两个指针动物在我的代码

Animal* animal1 
Animal* animal2 

我可以将它们相互比较。如果animal1和animal2具有不同的派生类,则比较应该产生错误。如果它们具有相同的派生类,则应返回比较运算符的输出。

有人可以指出我实现这个好方法吗?

哇,很多其他的答案是完全没有必要的。 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

由于没有与两个指针相关的静态类型信息,因此您需要使用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

使用type_info类。它定义了operator ==,它返回两种类型是否描述相同的类型。 在这里你可以找到参考:实现这个 http://www.cplusplus.com/reference/std/typeinfo/type_info/

的一种方法,是使用双调度“同一类”和“不同类”之间的区别:

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

这里有一个小窍门我使用(我希望它也能为你工作)。 我下面的私有方法添加到动物并在每一个派生类中重写它(我知道,它是有点麻烦,但它比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),因此速度很快。