Reputation: 459
I am trying to solve this problem but I don't know how to make conversion from interface class to my child class. Basicly, I am trying to make array of Vehicle pointers and elements of array to be child classes pointers, then pass element by element to Counter class method which will calculate value of total passengers, but I get compiler error:
invalid conversion from 'oss:Vehicle*' to 'oss::Bike*' [-fPermissive]
Here is my code:
Vehicle.h
using namespace std;
namespace oss{
class Vehicle
{
public:
virtual string type() = 0;
virtual unsigned passengers() = 0;
virtual ~Vehicle();
};
class Land_vehicle : public Vehicle{
protected:
string typeOfVehicle;
unsigned numberOfPassengers;
public:
Land_vehicle();
string type();
};
class Bike : public Land_vehicle{
public:
Bike();
unsigned passengers();
};
class Counter{
private:
int totalPassengers;
public:
Counter();
void add(Bike*b);
int total();
};
Vehicle.cpp
using namespace oss;
Vehicle::~Vehicle(){};
Land_vehicle::Land_vehicle(){typeOfVehicle = "Land";}
string Land_vehicle::type(){return typeOfVehicle;}
Bike::Bike(){numberOfPassengers = 1;}
unsigned Bike::passengers(){return numberOfPassengers;}
Counter::Counter(){totalPassengers = 0;}
void Counter::add(Bike b){
cout <<"inside add bike"<<endl;
totalPassengers += b.passengers();
}
int Counter::total(){return totalPassengers;}
Main.cpp
using namespace std;
using namespace oss;
int main()
{
Counter c;
Vehicle* v[] = {new Bike};
size_t sz = sizeof v/sizeof v[0];
for (unsigned i = 0; i < sz; ++i)
c.add(v[i]);
std::cout << "Total: " << c.total() << " passengers!" << std::endl;
for (unsigned i = 0; i < sz; ++i)
delete v[i];
return 0;
}
Upvotes: 2
Views: 2264
Reputation: 73376
According to your classes, every Bike
and every Car
are Vehicules. THis is why, whenever you need a
Vehicle*, you can use as well a
Bike*or a
Car*`.
You make use of this in your assignment:
Vehicle* v[] = {new Bike}; // yes a Bike* can be converted to a Vehicle*
However the reverse relation is not true. Not every Vehicle
is necessary a Bike
. This is why you can't just use a Vehicle*
when you need a Bike*
. To do the reverse condition you first have to check that the Vehicle
you're working with is indeed a Bike
, and if it's the case you can use casting.
Fortunately, your classes are polymorphic (due to the virtual functions). So you have to use a dynamic_cast()
to convert from parent (base) pointer to child (derived) pointer. But take care to check that the conversion succeeds (i.e. casted pointer isn't null).
You experience this and related problems, when you try to add a vehicle to your counter:
c.add(v[i]); // v[i] is a pointer to a vehicle, but which one
In fact there are several problems with your Counter::add()
:
c.add(*v[i])
. But the overload require that you tell at compile time which type of object it is (i.e. there's no add(Vehicle)
, and if there would be one, you'd suffer from object slicing)c.add(dynamic_cast<Bike*>(v[i]);
Now putting this together, here is how to modify your loop to add to the counter only bikes:
for (unsigned i = 0; i < sz; ++i) {
if (dynamic_cast<Bike*>(v[i]))
c.add(dynamic_cast<Bike*>(v[i]));
}
THis suppose to change the signature of add to:
void Counter::add(Bike* b){
cout <<"inside add bike"<<endl;
totalPassengers += b->passengers();
}
Here a live demo
If you have polymorphic classes, it's a pitty not to benefit from polymorphism:
class Counter {
int totalPassengers;
public:
Counter();
void add(Vehicle* b);
int total();
};
And the implementation of the redesigned function:
void Counter::add(Vehicle* b){
totalPassengers += b->passengers();
}
And this will work whatever the number of classes you derive from vehicle ! No longer need to add dozens of similar overloads of the same function.
Upvotes: 2