Предположим, у нас есть абстрактный класс с именем Vehicle
:
class Vehicle {
virtual bool raceWith(Vehicle *anotherVehicle) = 0;
};
И у нас есть свои подклассы Bicycle
а также Car
:
// forward declaration
class Car;
class Bicycle : public Vehicle {
virtual bool raceWith(Vehicle *anotherVehicle) {
throw SomeExceptionClass();
}
virtual bool raceWith(Car *anotherVehicle) {
return true;
}
virtual bool raceWith(Bicycle *anotherVehicle) {
return false;
}
};
Тем не менее, этот блок кода вызывает SomeExceptionClass:
Vehicle *aBicycle = new Bicycle();
Vehicle *aCar = new Car();
aBicycle->raceWith(aCar);
Что тут делать? Разве C ++ не позволяет нам использовать полиморфные методы таким образом?
Любая помощь будет оценена. Благодарю.
РЕДАКТИРОВАТЬ: Будет также хорошо дать ответ dynamic_cast<>
а также decltype
варианты?
Следующее будет Bicycle
с Vehicle
:
Vehicle *aBicycle = new Bicycle(); Vehicle *aCar = new Car(); aBicycle->raceWith(aCar);
Участвовать в гонке Bicycle
с Car
нам нужно использовать двойную отправку.
Чтобы сделать двойную отправку, мы используем this
указатель для вызова следующей функции, чтобы второй виртуальный вызов мог преобразоваться в правильный тип транспортного средства:
class Car;
class Bicycle;
class Vehicle {
public:
virtual bool raceWith(Vehicle& anotherVehicle) = 0;
virtual bool raceWith(Bicycle& anotherVehicle) = 0;
virtual bool raceWith(Car& anotherVehicle) = 0;
};class Bicycle : public Vehicle {
public:
virtual bool raceWith(Vehicle& anotherVehicle) override
{
//throw std::exception();
return anotherVehicle.raceWith(*this);
}
virtual bool raceWith(Car& anotherVehicle)
{
return true;
}
virtual bool raceWith(Bicycle& anotherVehicle)
{
return false;
}
};
class Car : public Vehicle {
public:
virtual bool raceWith(Vehicle& anotherVehicle) override
{
return true;
}
virtual bool raceWith(Car& anotherVehicle) override
{
return true;
}
virtual bool raceWith(Bicycle& anotherVehicle) override
{
return false;
}
};
int main()
{
Vehicle *aBicycle = new Bicycle();
Vehicle *aCar = new Car();
aBicycle->raceWith(*aCar);
}
Обратите внимание return anotherVehicle.raceWith(*this);
который выполнит второй виртуальный звонок.
Затем функции вызываются в следующем порядке:
main();
Bicycle::raceWith(Vehicle& anotherVehicle);
Car::raceWith(Bicycle& anotherVehicle);
Ниже приведена та же программа, но придерживающаяся использования указателей и исключений, как указано в вопросе:
#include <exception>
class Car;
class Bicycle;
class Vehicle {
public:
virtual bool raceWith(Vehicle* anotherVehicle) = 0;
virtual bool raceWith(Bicycle* bicycle) = 0;
virtual bool raceWith(Car* car) = 0;
};class Bicycle : public Vehicle {
public:
virtual bool raceWith(Vehicle* anotherVehicle) override
{
//throw std::exception();
return anotherVehicle->raceWith(this);
}
virtual bool raceWith(Car* car) override
{
return true;
}
virtual bool raceWith(Bicycle* bicycle) override
{
return false;
}
};
class Car : public Vehicle {
public:
virtual bool raceWith(Vehicle* anotherVehicle) override
{
throw std::exception();
}
virtual bool raceWith(Car* car) override
{
return true;
}
virtual bool raceWith(Bicycle* bicycle) override
{
return false;
}
};
int main()
{
Vehicle *aBicycle = new Bicycle();
Vehicle *aCar = new Car();
aBicycle->raceWith(aCar);
}
При выполнении
Vehicle *aBicycle = new Bicycle();
aBicycle->raceWith(aCar);
Тип автомобиля — Автомобиль (typeid(aCar).name()
), поэтому ваш компилятор вызывает метод с помощью Vehicle.
Пытаться
aBicycle->raceWith(static_cast<Car*>(aCar));
aBicycle->raceWith(dynamic_cast<Car*>(aCar));
Почему static_cast
или же dynamic_cast
Вы можете посмотреть этот пост на SO: Обычное приведение против static_cast против dynamic_cast
Попробуйте это, вы можете использовать динамическое приведение для определения типа для подкласса. Если вы продолжаете virtual bool raceWith(Vehicle *anotherVehicle)
как метод, наверное virtual bool raceWith(Car *anotherVehicle)
а также virtual bool raceWith(Bicycle *anotherVehicle)
никогда не будет казнен без кастинга, так как anotherVehicle
Тип транспортного средства obj. Надеюсь поможет 🙂
#include <iostream>
using namespace std;
class Car;
class Bicycle;
class Vehicle {
public:
//virtual bool raceWith(Vehicle *anotherVehicle) = 0;
virtual bool raceWith(Car *anotherVehicle) = 0;
virtual bool raceWith(Bicycle *anotherVehicle) = 0;
};
class Bicycle : public Vehicle {
/*virtual bool raceWith(Vehicle *anotherVehicle) {
throw SomeExceptionClass();
}*/
virtual bool raceWith(Car *anotherVehicle) {
cout << "will print" << endl;
return true;
}
virtual bool raceWith(Bicycle *anotherVehicle) {
return false;
}
};
class Car : public Vehicle {
/*virtual bool raceWith(Vehicle *anotherVehicle) {
throw SomeExceptionClass();
}*/
virtual bool raceWith(Car *anotherVehicle) {
return true;
}
virtual bool raceWith(Bicycle *anotherVehicle) {
return false;
}
};
int main()
{
Vehicle *aBicycle = new Bicycle();
Vehicle *aCar = new Car();
if (dynamic_cast<Bicycle*>(aCar) != NULL) {
std::cout << "Race with A Bicycle" << std::endl;
aBicycle->raceWith(static_cast<Bicycle*>(aCar));
}
else if (dynamic_cast<Car*>(aCar) != NULL) {
std::cout << "Race with A Car" << std::endl;
aBicycle->raceWith(static_cast<Car*>(aCar));
}
else {
//throw SomeExceptionClass();
}
//aBicycle->raceWith(aCar);
return 0;
}