我只是C ++的新手,并且做了一个实现一些继承的小项目。它基本上可以总结如下:
//.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;
}
输出:
can not eat
can not eat
答案 0 :(得分:11)
当你有这样的功能时:
void Carnivore::eat(Food f)
它的参数按值。这意味着提供了所提供对象的副本。
在这种情况下,您指定的是Food
类型,因此最终会得到一个Food
对象。没有神奇的多态性,没什么。只是一个标准的Food
对象。
这称为切片;请继续查阅这个术语,因为网上有大量内容。
简而言之,您可以通过接受对现有多态对象的引用来维护多态性的使用:
void Carnivore::eat(Food& f)
另外,下次请发一个最小的测试用例。这是一个巨大的代码片段!
祝你学习顺利。
答案 1 :(得分:5)
你将食物的价值传递到食物中。要使多态性工作,您需要通过引用或指针传递:
(通过指针:)
void Carnivore::eat(Food* f)
{
Meat* m = dynamic_cast<Meat*>(f);
if(m != 0) cout << "can eat\n";
else cout << "can not eat\n";
}
答案 2 :(得分:2)
这就是所谓的“切片问题”。您的函数正在对您传递的对象进行复制。副本由基类型的复制构造函数生成,并且您为派生类所做的任何特化都将丢失。
答案 3 :(得分:1)
对象切片是导致实现问题的原因。
您的eat()
函数应将引用引用至Food
或指针至Food
,如下所述:
virtual void eat(Food & f);
//usage
Meat meat;
animal.eat(meat);
或者
virtual void eat(Food * pf);
//usage
Meat meat;
animal.eat(&meat); //note &
答案 4 :(得分:1)
C ++的运行时多态(又称虚函数调用/虚拟调度)要求通过指针或对基类的引用来调用函数。在这里,你的eat函数接受一个Food参数按值 ...复制或切片 * f值的一部分并创建一个新的Food
对象。这些对象永远不能由dynamic_cast<Meat*>
投放,因为Meat
部分已被切断。只需更改为Carnivore::eat(const Food& f)
即可生效....