C++ 对基向量的元素调用派生方法(给出的示例)
假设我有下面的类结构。我希望能够确定我的动物向量中的元素是什么类型的类,这样我就可以对它执行特定于子类的方法。以下示例应说明:C++ 对基向量的元素调用派生方法(给出的示例),c++,vector,derived,object-slicing,C++,Vector,Derived,Object Slicing,假设我有下面的类结构。我希望能够确定我的动物向量中的元素是什么类型的类,这样我就可以对它执行特定于子类的方法。以下示例应说明: #include <iostream> #include <vector> using namespace std; class Animal { public: int foodcount; Animal() { foodcount = 0; cout << "An an
#include <iostream>
#include <vector>
using namespace std;
class Animal {
public:
int foodcount;
Animal() {
foodcount = 0;
cout << "An animal was created.\n";
}
virtual ~Animal() {
cout << "An animal was destroyed.\n";
}
};
class Lion : public Animal {
public:
Lion() {
cout << "A lion was created.\n";
}
virtual ~Lion() {
cout << "A lion was destroyed.\n";
}
void chowMeat(int howmuch) {
foodcount += howmuch;
}
};
class Butterfly : public Animal {
public:
Butterfly() {
cout << "A butterfly was created.\n";
}
virtual ~Butterfly() {
cout << "A butterfly was destroyed.\n";
}
void drinkNectar(int howmuch) {
foodcount += howmuch;
}
};
int main() {
Animal* A = new Lion();
Animal* B = new Butterfly();
vector<Animal*> v;
v.push_back(A);
v.push_back(B);
// a little later
for (int i=0; i<v.size(); i++) {
if (v[i] is a Lion) v[i]->chowMeat(); // will not work of course
if (v[i] is a Butterfly) v[i]->drinkNectar(); // will not work of course
}
std::cin.get();
return 0;
}
循环的目的是什么?是为了吃东西吗?在这种情况下,向基类添加一个
virtualvoid-eat(int-howmount)
,并在派生类中重写该函数。理想情况下,您应该向基类添加一个虚拟函数,void-eat(int-quantity)
并在派生类中重写该函数
在这种情况下,甚至可以将函数设为非虚拟函数并在基类中实现它,因为两个派生类做的事情完全相同
除此之外,您可以使用dynamic\u cast
测试对象的动态类型:
if (Lion* lion = dynamic_cast<Lion*>(v[i])) {
lion->chowMeat(42);
}
else if (Butterfly* butterfly = dynamic_cast<Butterfly*>(v[i])) {
butterfly->drinkNectar(42);
}
// etc.
if(Lion*Lion=dynamic_cast(v[i])){
狮子肉(42);
}
else if(蝶形*蝶形=动态(v[i])){
蝴蝶->饮水机(42);
}
//等等。
(在另一个注释中,您将非常小心地使用C++中的裸指针;在手动管理资源时,很难编写正确的代码。在示例中,您没有释放由类动物{
公众:
国际食品计数;
动物(){
foodcount=0;
cout如果示例真正具有代表性,那么虚拟函数将更巧妙地解决您眼前的问题
在任何情况下,如果类具有虚拟函数,最简单的答案是使用dynamic\u cast
检查对象是否属于给定类型。例如:
for (int i=0; i<v.size(); i++) {
if (Lion *lion = dynamic_cast<Lion *>(v[i]))
lion->chowMeat();
else if(Butterfly *butterfly = dynamic_cast<Butterfly *>(v[i]))
butterfly->drinkNectar();
}
for(inti=0;ichowMeat();
else if(蝶形*蝶形=动态(v[i]))
蝴蝶->饮水机();
}
它内置于语言中,只是用于检查指向base的指针是否实际指向派生类型更高的对象
另一种选择是在基类中使用某种类型的虚拟GetType函数,在每个类中重写该函数,以返回唯一标识该类的内容(整数、对象等)。然后在运行时调用该函数,并检查结果以找出指向的对象的类型
dynamic\u cast
具有内置于该语言中的优点,无需您努力支持。使用自己的函数在各种编译器中具有更可预测的性能特征,允许您存储数据,而不仅仅是对象的实际类型,但您必须全部编写你自己。如果你不打算使用虚拟方法让两个动物都有一个方法,为什么还要让它们成为animal的子类。eat()。它们需要不同的方法名来做相同的事情有什么原因吗?那么它们就不应该从同一个类继承。dynamic\u-cast
是“如何正确地做”。这是“不恰当的”因为在这里使用它意味着“没有遵循你应该遵循的设计原则”。Java的等价物是“untty”出于同样的原因,考虑到它是如何编写的,这一点更为明显。顺便说一下,请使用foreach
类型构造来迭代容器,或者至少使用真正的迭代器而不是索引。另请参见.falmari:+1-子类型化的目的是泛化。当狮子吃肉和蝴蝶喝花蜜时,它们它们都在自己进食。一般的描述是它们都是在进食的动物。所以我们有一个虚拟的void eat()
,并实现它,让狮子通过吃肉来进食,蝴蝶通过喝花蜜来进食。(我想你可以称之为feedSelf()
,但这是不必要的尴尬。)啊,我应该把这个例子说得更清楚。我的意思是,这些方法将是独特的,可以做完全不同的事情。但是感谢dynamic_cast的回答——还有其他更漂亮的方法来重组它吗?@Schreib:我不认为这很难看。有时需要使用dynamic_cast
,使用它也不是绝对错误的当然,您可以实现自己的类型标识系统(例如,使用一个基类GetType()
函数,该函数返回一个唯一标识符,您可以使用该标识符来确定类型),但是,当语言内置了类型标识时,为什么要滚动您自己的类型标识呢?“有时是必要的,但并非绝对错误”绝对不是对“丑陋”指控的辩护:)@Karl:不,不是。我不认为这很丑陋,我试图先发制人地对付反演员狂热分子。
class Animal {
public:
int foodcount;
Animal() {
foodcount = 0;
cout << "An animal was created.\n";
}
virtual ~Animal() {
cout << "An animal was destroyed.\n";
}
virtual void eat(int howMuch) {
foodcount += howmuch;
}
};
class Lion : public Animal {
public:
virtual void eat(int howmuch) {
Animal::eat(howmuch + 19);
}
};
class Butterfly : public Animal {
void eat(int howmuch) {
Animal::eat(howmuch / 1000);
}
};
class Tribble: public Animal
{
void eat(int howmuch) {
throw DontFeedTribles();
}
};
int main() {
std::auto_ptr<Animal> A = new Lion();
std::auto_ptr<Animal> B = new Butterfly();
vector<Animal*> menagerie;
menagerie.push_back(A.get());
menagerie.push_back(B.get());
BOOST_FOREACH(Animal* animal, menagerie)
{
animal->eat(10000);
}
std::cin.get();
return 0;
}
for (int i=0; i<v.size(); i++) {
if (Lion *lion = dynamic_cast<Lion *>(v[i]))
lion->chowMeat();
else if(Butterfly *butterfly = dynamic_cast<Butterfly *>(v[i]))
butterfly->drinkNectar();
}