Как правильно осуществить сравнение для базового класса? - PullRequest
6 голосов
/ 18 сентября 2010

У меня есть базовый класс

class Animal 

с чисто виртуальными функциями и набором производных классов

class Monkey : public Animal 
class Snake : public Animal

Я хочу реализовать операцию сравнения, чтобы при обнаружении двух указателей на Животные в моем коде

Animal* animal1
Animal* animal2

Я могу сравнить их друг с другом. Сравнение должно давать ложь, если animal1 и animal2 относятся к разным производным классам. Если они принадлежат к одному и тому же производному классу, должен быть возвращен вывод оператора сравнения.

Может кто-нибудь указать мне хороший способ реализации этого?

Ответы [ 5 ]

4 голосов
/ 19 сентября 2010

Ух ты, многие другие ответы были совершенно ненужными.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;
    }
};

Edit: поклон перед моей автоматической шаблонной реализацией!

Edit edit: Одна вещь, которую я сделал, это забыл пометить их как const, что былонеправильно со мной.Я не буду извиняться за то, что не сделал! = Поскольку, давайте посмотрим правде в глаза, реализация этого - полная пустяк.

Больше правок: это не пример того, как писать! = Или ==, это примеркак использовать CRTP.

4 голосов
/ 18 сентября 2010

Один из способов реализовать это - использовать двойную диспетчеризацию для различения «одного класса» и «разных классов»:

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); }
};
3 голосов
/ 18 сентября 2010

Поскольку с этими двумя указателями нет статической информации о типе, вам нужно будет использовать RTTI .Вы можете сравнить результаты типа typeid operator , чтобы определить, относятся ли объекты к одному и тому же типу.

Альтернативой может быть добавление собственного идентификатора типа в класс Animal,Добавьте еще одну виртуальную функцию, и производные классы возвращают что-то, что однозначно идентифицирует тип.Вы можете использовать перечисление или имя типа в виде строки.Если вы можете использовать его, RTTI будет намного лучше, ИМХО.

2 голосов
/ 18 сентября 2010

Использовать класс type_info.Он определяет operator ==, который возвращает, описывают ли два типа один и тот же тип.Здесь вы можете найти ссылку: http://www.cplusplus.com/reference/std/typeinfo/type_info/

0 голосов
/ 19 сентября 2010

Вот небольшой трюк, которым я пользуюсь (надеюсь, он вам тоже подойдет). Я добавляю следующий закрытый метод к Animal и перезаписываю его в каждом производном классе (я знаю, это немного проблем, но он быстрее, чем 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 для каждого из указателей), поэтому оно довольно быстрое.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...