Я пытаюсь переопределить оператор виртуального сравнения в подклассе, но получаю ошибку компилятора, говорящую, что производный класс не реализует виртуальный оператор базового класса.
У меня есть ощущение, что это связано с тем, что мой производный оператор не использует тип аргумента базового класса.
Упрощенная версия выглядит следующим образом:
struct Base {
virtual bool operator ==(const Base) const;
};
struct Derived : Base {
bool operator ==(const Derived) const {
// implementation goes here
}
};
Есть ли способ для меня, или я должен сделать проверку типа в Derived
реализация, чтобы увидеть, если это правильный тип?
У меня есть ощущение, что это связано с тем, что мой производный оператор
не использует тип аргумента базового класса.
Точно так. Базовый класс должен принимать const ссылка (чтобы он мог иметь динамический тип Derived
и затем вы объявляете переопределение как:
bool operator ==(const Base& rhs) const {
const auto pRhs = dynamic_cast<const Derived*>(&rhs);
if (pRhs == nullptr)
{
return false; // Not a derived. Cannot be equal.
}
// Derived/Derived implementation goes here
}
Но будьте осторожны: такой виртуальный оператор сравнения очень легко ошибиться. Вам нужен хороший мотивирующий пример, чтобы сделать это так. В частности, если вы напишите:
Derived d;
Base b;
if (d == b) // All is well - derived override called, and returns false.
if (b == d) // Uh-oh! This will call the *base* version. Is that what you want?
Также:
Derived d;
DerivedDerived dd;
if (d == dd) // Did you want to use the DerivedDerived comparison?
В реализации Derived необходимо ввести проверку того, что параметр имеет ожидаемый тип.
Для операторов вы можете предпочесть определить виртуальный стандартный метод, а затем реализовать свои операторы, вызвав этот метод. Это позволяет избежать неожиданных или слишком больших подписей для операторов.
struct Base {
virtual int compare(const Base& source) const { return 0; }
bool operator ==(const Base& source) const
{ return compare(source) == 0; }
};
struct Derived : Base {
int compare(const Base& asource) const override
{ const Derived* source = dynamic_cast<const Derived*>(&asource);
int result = -2;
if (source) { ... result = ...; }
return result;
}
// redefinition to force the expected/right signature at this level
bool operator==(const Derived& source) const
{ return compare(source) == 0; }
};