实现基类比较的正确方法是什么?
我有一个基类实现基类比较的正确方法是什么?
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的例子。如果你不喜欢我选择实施我的!=或==,你可以起诉。
由于没有与两个指针相关的静态类型信息,因此您需要使用RTTI。您可以比较类型typeid
operator的结果以确定对象是否属于同一类型。
另一种方法是将您自己的类型ID添加到Animal
类。添加另一个虚函数并派生类返回唯一标识类型的内容。您可以使用枚举,或者可以使用字符串的名称。如果你可以使用它,但是,RTTI会好得多恕我直言。
+1。另外--RTTI会产生一些运行时开销(显然),尽管不会太多。如果你的应用程序有大量的类,并且你只需要在几个地方使用RTTI,那么我会用专门的类型识别功能来解决你自己的解决方案。但是,如果RTTI的使用很普遍,那么您应该使用自己的方法来使用它。 – 2010-09-18 19:42:45
我认为双重调度可能是一个更好的方法来做到这一点比手动摆弄'std :: type_info'对象。无论如何,一旦你知道这是正确的类型,你会怎么做?您仍然必须将指针转换为派生类的指针。由于C++仅运行最小的RTTI,因此您可能不得不切换类型。而一种类型的切换通常强烈表明有人最好使用“虚拟”功能。 – sbi 2010-09-18 20:08:10
@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); }
};
你能解释一下使用Animal :: compare_impl的行吗?手段?到目前为止,我只在“using namespace foo”中看到关键字“using”。 – Hans 2010-09-18 20:01:30
@Hans:它将一个基类的标识符带入派生类的范围,防止派生类重载隐藏基类函数。 – sbi 2010-09-18 20:05:07
他的'使用'声明做了两件事: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),因此速度很快。
是的,与运营商==超载更好。 – imaginaryboy 2010-09-18 22:09:41
虽然小错误,需要是'const monkey * p = dynamic_cast(&other)'和'return * this == * p' ...引用不能转换为'bool'。 –
imaginaryboy
2010-09-18 22:22:35
@imaginaryboy:是的,我解决了一个更好的解决方案。 – Puppy 2010-09-18 22:28:24