В вашем примере есть несколько проблем, помимо основных.Я начну с мелких проблем, чтобы устранить их.
- Вам нужно объявить
equals
как virtual
в базовом классе. В отличие от Java , динамическая диспетчеризация не по умолчанию в C ++, но должна запрашиваться для метода с использованием атрибута virtual
, например:
class Object {
public:
virtual bool equals(Object other) {
throw "Not implemented";
}
}
Вы передаете объект, который вы сравниваете с
по значению .
В отличие от Java , в C ++ даже типы классов могут передаваться по значению.Это означает, что функция
equals
получает копию
Object
для сравнения с - и
просто с этим.Части объекта, с которым вы хотите сравнить, включая элемент
value
, не копируются в аргумент, передаваемый
equals
.Вы должны передать параметр
по ссылке .Поскольку вашей функции
equals
не требуется изменять объект, с которым вы сравниваете, достаточно ссылки без разрешения записи (обычно называемой
const reference из-за синтаксиса):
class Object {
public:
virtual bool equals(const Object& other) {
throw "Not implemented";
}
}
Если вы пишете базовый класс, который просто предоставляет сигнатуру функции, которую необходимо переопределить в каждом производном классе, вы не заставляете его что-то выдавать, а вместо этого делаете его абстрактным, объявляя его чистым
виртуальная функция с использованием синтаксиса
=0
.Это предотвращает случайное создание
Object
экземпляров, которые нельзя сравнивать.Это могло бы отразить пропущенную передачу по ссылке:
class Object {
public:
virtual bool equals(const Object& other) = 0;
}
Теперь давайте ответим на ваш вопрос:
Этот подход работает в динамически типизированных языках, таких как JavaScript или Python, ноэто не работает в C ++. Во время компиляции компилятор должен знать, где он находит элемент value
в объекте other
и его тип.Если вы просто передадите любой Object
, компилятор не сможет это узнать.И даже вы не знаете: тип может быть int
или float
.Так что ни вы, ни компилятор не знают, есть ли в объекте, который вы передаете для сравнения, значение с плавающей запятой или значение int.Если объекты Integer
должны быть сопоставимы как с объектами Integer
, так и Float
, вам необходимо либо использовать методы сравнения, либо вам нужен способ получить общий value
общего типа.В этом случае на машинах с 32-разрядными целыми числами каждое целочисленное значение точно представляется в переменной double
.Вы можете добавить в класс Object
вторую функцию с именем as_double
следующим образом:
class Object {
public:
virtual bool equals(const Object &other) const = 0;
virtual double as_double() const = 0;
}
Я также пометил методы const
, что означает, что вы можете вызывать их на объектах или использовать ссылки, которые вы можетене пишите.Теперь вы можете реализовать Integer
и Float
следующим образом:
class Integer: public Object {
public:
int value;
Integer(int val) {
value = val;
}
bool equals(const Object & other) const {
return value == other.as_double();
}
double as_double() const {
return value;
}
};
class Float: public Object {
public:
double value;
Float(double val) {
value = val;
}
bool equals(const Object & other) const {
return value == other.as_double();
}
double as_double() const {
return value;
}
};
И, если вы посмотрите на метод equals
, он теперь почти одинаков для обоих типов: вы извлекаете значение аргументакак double, и сравните его с локальным значением (в случае Integer
локальное значение тоже неявно преобразуется в double. Таким образом, вы также можете использовать универсальную реализацию сравнения, которая вызывает to_double
для обоих объектов, и выне нужно беспокоиться о реализации equals
в каждом подклассе:
class Object {
public:
bool equals(const Object& other) const {
return as_double() == other.as_double();
}
virtual double as_double() const = 0;
}
Обратите внимание, это работает только потому, что double
на самом деле может представлять все значения, даже те, которые хранятся в Integers
.Фактический вариант использования не имеет такого общего типа, который вы можете преобразовать, вам нужно более сложное решение.