动态转换C ++的奇怪问题

时间:2011-05-09 15:45:42

标签: c++

我只是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

5 个答案:

答案 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)即可生效....