Reputation: 3278
Assume we have an abstract class called Vehicle
:
class Vehicle {
virtual bool raceWith(Vehicle *anotherVehicle) = 0;
};
And we have its subclasses Bicycle
and 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;
}
};
However, this block of code throws SomeExceptionClass:
Vehicle *aBicycle = new Bicycle();
Vehicle *aCar = new Car();
aBicycle->raceWith(aCar);
What to do here? Does not C++ allow us to use polymorphic methods in this manner?
Any help will be appreciated. Thanks.
EDIT: It will be also good to provide an answer with dynamic_cast<>
and decltype
variants?
Upvotes: 2
Views: 71
Reputation: 109
Try this, you can use dynamic cast to detect the type for subclass. If you keep virtual bool raceWith(Vehicle *anotherVehicle)
as a method, probably virtual bool raceWith(Car *anotherVehicle)
and virtual bool raceWith(Bicycle *anotherVehicle)
will never get executed without casting since anotherVehicle
is a Vehicle type obj. Hope will help :)
#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;
}
Upvotes: 1
Reputation: 11022
The following will race a Bicycle
with a Vehicle
:
Vehicle *aBicycle = new Bicycle(); Vehicle *aCar = new Car(); aBicycle->raceWith(aCar);
To race a Bicycle
with a Car
we need to use double dispatch.
To make double dispatch work we use the this
pointer to call the next function so that the second virtual call can resolve to the correct type of vehicle:
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);
}
Note the return anotherVehicle.raceWith(*this);
which will perform the second virtual call.
The functions are then called in this order:
main();
Bicycle::raceWith(Vehicle& anotherVehicle);
Car::raceWith(Bicycle& anotherVehicle);
The following is the same program, but sticking with the use of pointers and exceptions as provided in the question:
#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);
}
Upvotes: 4
Reputation: 490
By doing
Vehicle *aBicycle = new Bicycle();
aBicycle->raceWith(aCar);
The type of aCar is Vehicle (typeid(aCar).name()
), so your compiler is calling the method with Vehicle.
Try
aBicycle->raceWith(static_cast<Car*>(aCar));
aBicycle->raceWith(dynamic_cast<Car*>(aCar));
As for why static_cast
or dynamic_cast
, you can look at this post on SO: Regular cast vs. static_cast vs. dynamic_cast
Upvotes: 1