У вашего кода большая проблема в том, что его нелегко расширить (нарушает принцип открытия / закрытия ).Однако вы можете делегировать сравнение методу базового класса.
Кроме того, если вы захотите применить семантику (это хорошо), вы не сможете обойти даункинг, извините.
Чтобы сделать его надежным и расширяемым,
- Сделать базовый метод чисто виртуальным
- Обеспечить реализацию базового метода (да, это работает! Даже если он чисто виртуальный), который сравниваеттипы объектов
- В производных классах используйте реализацию базового класса для проверки на равенство типов, а затем выполните фактическую проверку логики.
#include <iostream>
#include <iomanip>
#include <string>
#include <typeinfo>
struct vehicle {
virtual bool compare_to(vehicle const& other) const = 0;
};
bool vehicle::compare_to(vehicle const& other) const {
return typeid(*this) == typeid(other);
}
struct car : vehicle {
std::string color;
car(std::string const& color) : color(color) { }
bool compare_to(vehicle const& other) const {
bool result = vehicle::compare_to(other);
return result and (color == static_cast<car const&>(other).color);
}
};
struct bike : vehicle {
int spokes;
bike(int spokes) : spokes(spokes) { }
bool compare_to(vehicle const& other) const {
bool result = vehicle::compare_to(other);
return result and (spokes == static_cast<bike const&>(other).spokes);
}
};
int main() {
car c1("blue");
car c2("red");
bike b1(42);
std::cout << std::boolalpha;
std::cout << c1.compare_to(c2) << "\n"
<< c1.compare_to(b1) << "\n"
<< c1.compare_to(c1) << "\n";
}
Приведенный выше кодstatic_cast
безопасен, так как мы заранее убедились, что тип один и тот же, поэтому приведение никогда не завершится неудачей.
Обратите внимание, что использование typeid
здесь совершенно законно.Это даже не должно быть очень неэффективно, так как нет никакой глубокой иерархии типов, чтобы идти.Но если вы хотите сделать это более эффективным, вы можете реализовать простой собственный механизм, который использует статическую таблицу в базовом классе для сопоставления каждого созданного экземпляра с уникальным идентификатором типа (например, std::map<vehicle*, type_id>
, где type_id
- это простой старыйenum
) и выполните простой поиск.
… Или используйте dynamic_cast
, на самом деле.