开发者

What is the correct way to implement the comparison for a base class?

开发者 https://www.devze.com 2023-01-17 04:17 出处:网络
I have a base class class Animal with pure virtual functions, and a set of derived classes class Monkey : public A开发者_如何学Gonimal

I have a base class

class Animal 

with pure virtual functions, and a set of derived classes

class Monkey : public A开发者_如何学Gonimal 
class Snake : public Animal

I want to implement a comparison operation so that, if I encounter two pointers to Animals in my code

Animal* animal1
Animal* animal2

I can compare them to each other. The comparison should yield false, if animal1 and animal2 are of different derived classes. If they are of the same derived class, the output of the comparison operator should be returned.

Can someone point me to a good way of implementing this?


Wow, a lot of the other answers were so totally unnecessary. dynamic_cast- it exists, use it.

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;
    }
};

Edit: Bow before my automatic templated implementation!

Edit edit: One thing I did do was forget to tag them as const, which was wrong of me. I will not apologize for not doing != as, let's face it, implementing it is a total doddle.

More edits: this is not an example on how to write != or ==, it's an example of how to use the CRTP.


One way to implement this, is to use double-dispatch to differentiate between 'same class' and 'different classes':

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); }
};


Since there is no static type information associated with the two pointers, you will need to use RTTI. You can compare the results of type typeid operator to determine if the objects are of the same type.

An alternative would be to add your own type ID to the Animal class. Add another virtual function and have derived classes return something that uniquely identifies the type. You could use an enumeration, or maybe the name of the type as a string. If you can use it, though, RTTI would be much better IMHO.


Use type_info class. It defines operator== which return whether the two types describe the same type. Here you can find reference: http://www.cplusplus.com/reference/std/typeinfo/type_info/


Here is a little trick I use (I hope it can work for you too). I add the following private method to Animal and OVERRIDE it in every derived class (I know, it's a little bit of trouble, but it is faster than 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;
 }
...
}

now in order to see if 2 pointers (a and b) are of the same class just check for

a->signature()==b->signature()

It's not really a solution, it's a trick, but it works with just 2 virtual method calls (1 for each of the pointers) so it is rather fast.

0

精彩评论

暂无评论...
验证码 换一张
取 消