对基向量的元素调用派生方法(给出的示例)

发布于 2024-10-06 12:39:32 字数 1665 浏览 8 评论 0原文

假设我有以下类结构。我希望能够确定 Animal 向量中的元素是什么类类型,以便我可以对其执行特定于子类的方法。下面的例子应该演示:

#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;
}

显然标记的代码不起作用,但是我该如何做我想做的事情呢?是否有我应该遵循但没有遵循的解决方法或设计原则?我研究过dynamic_cast,但明白这很不漂亮。那么我应该怎样做才正确呢?

在Java中,我会这样做:

if (v.get(i).getClass() == Lion.class) {
    ((Lion)v.get(i)).chowMeat();
}
if (v.get(i).getClass() == Butterfly.class) {
    ((Butterfly)v.get(i)).drinkNectar();
}

Suppose that I have the following structure of classes. I want to be able to determine of what class type the element in my Animal vector is, so that I may perform subclass-specific methods on it. The example below should demonstrate:

#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;
}

Obviously the marked code won't work, but how do I do what I want to do? Is there a workaround or a design principle that I should follow but am not? I've looked into dynamic_cast but understand that is unpretty. So how should I do it correctly?

In Java, I would do this:

if (v.get(i).getClass() == Lion.class) {
    ((Lion)v.get(i)).chowMeat();
}
if (v.get(i).getClass() == Butterfly.class) {
    ((Butterfly)v.get(i)).drinkNectar();
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

似最初 2024-10-13 12:39:32

理想情况下,您可以向基类添加一个虚函数 void eat(int amount) 并在派生类中重写该函数。

在这种情况下,使该函数成为非虚拟函数并在基类中实现它甚至可能是有意义的,因为两个派生类都执行完全相同的操作。

除此之外,您可以使用 dynamic_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.

另一方面,您需要非常小心地在 C++ 中使用裸指针;编写正确的代码非常困难在您手动管理资源的情况下,您尚未释放 AB 指向的对象,因此考虑使用智能指针,例如 <。 code>shared_ptr,自动管理您的资源。)

Ideally you would add a virtual function to the base class, void eat(int quantity) and override that function in the derived classes.

In this case, it might even make sense to make the function non-virtual and implement it in the base class, since both derived classes do the exact same thing.

Barring that, you can use dynamic_cast to test the dynamic type of the object:

if (Lion* lion = dynamic_cast<Lion*>(v[i])) {
    lion->chowMeat(42); 
}
else if (Butterfly* butterfly = dynamic_cast<Butterfly*>(v[i])) {
    butterfly->drinkNectar(42);
}
// etc.

(On a different note, you'll want to be very careful using naked pointers in C++; it's very difficult to write correct code where you manage resources manually. In your example, you haven't freed the objects pointed to by A and B and have thus leaked them. Consider using smart pointers, like shared_ptr, to manage your resources automatically.)

_蜘蛛 2024-10-13 12:39:32

循环的目的是什么?是为了吃东西吗?在这种情况下,请将 virtual void ConsumerFood(int howMuch) 添加到您的基类,并在派生类中重写它。

What is the purpose of the loop? Is it to consume food? In that case, add a virtual void consumeFood(int howMuch) to your base class, and override that in your derived classes.

孤星 2024-10-13 12:39:32

如果这个例子确实具有代表性,那么虚拟函数将更巧妙地解决您眼前的问题。

无论如何,如果您的类具有虚函数,最简单的答案是使用dynamic_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();
}

它是内置于语言中的,只是用于检查指向基类的指针是否实际上指向更派生类型的对象。

另一种选择是在基类中拥有某种虚拟 GetType 函数,您可以在每个类中重写该函数以返回唯一标识该类的内容(整数、对象等)。然后,您在运行时调用此函数,并检查结果以找出所指向的对象类型。

dynamic_cast 的优点是内置于语言中,并且不需要您付出任何努力来支持。使用自己的函数在各种编译器中具有更可预测的性能特征,并且允许存储除对象实际类型之外的数据 - 但您必须自己编写所有数据。

If the example is genuinely representative, a virtual function would solve your immediate problem much more neatly.

In any event, the simplest answer, if your classes have virtual functions, is to use dynamic_cast to check whether an object is of a given type. For example:

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();
}

It is built in to the language, and is just the thing for checking whether a pointer to base actually points to an object of a more derived type.

The other option is to have some kind of virtual GetType function in your base class, which you override per class to return something (an integer, an object, whatever) that uniquely identifies that class. Then you call this function at runtime, and examine the result to find out what sort of object is being pointed at.

dynamic_cast has the advantage of being built in to the language, and requires no effort on your part to support. Using one's own function has more predictable performance characteristics across a wide range of compilers and allows one to store data other than simply what type the object really is -- but you do have to write it all yourself.

勿忘心安 2024-10-13 12:39:32

为什么不吃()?

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;
}

Why not eat()?

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;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文