Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I have a base class

class Animal 

with pure virtual functions, and a set of derived classes

class Monkey : public Animal 
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?

like image 879
Hans Avatar asked Sep 18 '10 19:09

Hans


People also ask

What is base class method?

A base class access is permitted only in a constructor, an instance method, or an instance property accessor. It is an error to use the base keyword from within a static method. The base class that is accessed is the base class specified in the class declaration.

Which is most appropriate definition of a base class?

Which is most appropriate definition of a base class? Explanation: A class which is parent of another class, or from which other classes can be derived, is known as a base class. It is mandatory that a class must have at least one derived class to be called as a base class.

What is the difference between base class and derived class?

The class whose members are inherited is called the base class, and the class that inherits those members is called the derived class.

What is base class explain with example?

A class derived from a base class inherits both data and behavior. For example, "vehicle" can be a base class from which "car" and "bus" are derived. Cars and buses are both vehicles, but each represents its own specialization of the vehicle base class.


2 Answers

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.

like image 100
Puppy Avatar answered Oct 15 '22 09:10

Puppy


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); }
};
like image 21
Bart van Ingen Schenau Avatar answered Oct 15 '22 10:10

Bart van Ingen Schenau