Strange problem with dynamic cast C++ [closed]
I'm just new to C++, and doing a small project which i开发者_JAVA技巧mplementing some inheritance. It can basically be summarized below:
//.h file
class Food{
public:
Food();
virtual ~Food();
};
class Animal{
public:
Animal();
virtual ~Animal();
virtual void eat( Food f);
};
class Meat : public Food{
public:
Meat();
~Meat();
};
class Vegetable : public Food{
public:
Vegetable();
~Vegetable();
};
class Carnivore : public Animal{
public:
Carnivore();
~Carnivore();
void eat(Food f);
};
//.cpp file
Food::Food()
{
do something;
}
Food:~Food()
{
do something;
}
Animal::Animal()
{
do something;
}
Animal::~Animal()
{
do something;
}
Meat::Meat()
{
do something;
}
Meat::~Meat()
{
do something;
}
Vegetable::Vegetable()
{
do something;
}
Vegetable::~Vegetable()
{
do something;
}
Carnivore::Carnivore()
{
do something;
}
Carnivore::~Carnivore()
{
do something;
}
void Carnivore::eat(Food f)
{
Meat* m = dynamic_cast<Meat*>(&f);
if(m != 0) cout << "can eat\n";
else cout << "can not eat\n";
}
//main.cpp
int main()
{
Animal* a;
Food* f;
Meat m;
Vegetable v;
Carnivore c;
a = &c;
f = &v;
a->eat(*f);
f = &m;
a->eat(*f);
return 1;
}
And the output:
can not eat
can not eat
When you have a function like this:
void Carnivore::eat(Food f)
it takes its parameter by value. That means a copy of the provided object is made.
In this case, you're specifying a type Food
, so you end up with a Food
object. No magic polymorphism, nothing. Just a bog-standard Food
object.
This is known as slicing; please go ahead and look up this term, as there is loads of stuff about it on the web.
In short, though, you can maintain the use of polymorphism by accepting a reference to the existing polymorphic object:
void Carnivore::eat(Food& f)
Also, next time please post a minimal testcase. That's a huge snippet of code!
Good luck with your studies.
You're passing food by value into the eating function. For polymorphism to work you need to pass either by reference or by pointer:
(by pointer:)
void Carnivore::eat(Food* f)
{
Meat* m = dynamic_cast<Meat*>(f);
if(m != 0) cout << "can eat\n";
else cout << "can not eat\n";
}
This is what's known as the "slicing problem". Your functions are taking a copy of the object you pass. The copy is being generated by the copy constructor for the base type, and any specialization you've done for the derived class is lost.
Object slicing is what causing the problem in your implementation.
Your eat()
function should take either reference to Food
or pointer to Food
as explained below:
virtual void eat(Food & f);
//usage
Meat meat;
animal.eat(meat);
Or
virtual void eat(Food * pf);
//usage
Meat meat;
animal.eat(&meat); //note &
C++'s run-time polymorphism (aka virtual function calls / virtual dispatch) requires that the functions be called via a pointer or reference to a base class. Here, your eat function takes a Food argument by value... which copies or slices the part of the *f value and creates a new Food
object. Such objects can never be casted by dynamic_cast<Meat*>
, because the Meat
part has been chopped off. Just change to Carnivore::eat(const Food& f)
and it will work....
精彩评论