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++中的裸指针;在手动管理资源时,很难编写正确的代码。在示例中,您没有释放由 < <代码> >代码> B/COD>指向的对象,并因此泄漏了它们。请考虑使用诸如指针>自动管理您的资源。)

为什么不吃()

类动物{
公众:
国际食品计数;
动物(){
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();
}