Представьте, что у меня есть абстрактный базовый класс Shape
, с производными классами Circle
и Rectangle
.
class Shape {};
class Circle : public Shape {};
class Rectangle : public Shape {};
Мне нужно определить, равны ли две фигуры, предполагая, что у меня есть два указателя Shape*
. (Это потому, что у меня есть два экземпляра vector
и я хочу посмотреть, есть ли у них одинаковые фигуры)
Рекомендуемый способ сделать это - double dispatch. Что я придумал, так это следующее (здесь все значительно упрощено, так что фигуры равны всем другим фигурам того же типа):
class Shape {
public:
virtual bool equals(Shape* other_shape) = 0;
protected:
virtual bool is_equal(Circle& circle) { return false; };
virtual bool is_equal(Rectangle& rect) { return false; };
friend class Circle; // so Rectangle::equals can access Circle::is_equal
friend class Rectangle; // and vice versa
};
class Circle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
protected:
virtual bool is_equal(Circle& circle) { return true; };
};
class Rectangle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
protected:
virtual bool is_equal(Rectangle& circle) { return true; };
};
Это работает, но я должен добавить отдельную функцию equals
и объявление friend
в Shape
для каждого производного класса. Затем я должен скопировать-вставить точно такую же равно
функцию в каждый производный класс тоже. Это ужасное количество шаблонов, скажем, 10 разных форм!
dynamic_cast
не обсуждается; слишком медленно. (Да, я проверил его. Скорость имеет значение в моем приложении.)
Я пробовал это, но это не работает:
class Shape {
public:
virtual bool equals(Shape* other_shape) = 0;
private:
virtual bool is_equal(Shape& circle) { return false; };
};
class Circle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
private:
virtual bool is_equal(Circle& circle) { return true; };
};
class Rectangle : public Shape {
public:
virtual bool equals(Shape* other_shape) { return other_shape->is_equal(*this); };
private:
virtual bool is_equal(Rectangle& circle) { return true; };
};
equals()
всегда возвращает false, даже на одинаковых фигурах. Кажется, что диспетчерская всегда выбирает базовую функцию is_equal(Shape&)
, даже когда доступно "более точное" совпадение. Возможно, в этом есть смысл, но я не достаточно хорошо понимаю диспетчерскую C++, чтобы понять почему.