首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在一个数据结构中存储多态类型

在一个数据结构中存储多态类型
EN

Stack Overflow用户
提问于 2014-04-02 09:46:32
回答 4查看 223关注 0票数 0

你有动物收容所。庇护所可以储存可变数量的动物。你把很多动物(狗和猫)放进收容所。

然后你告诉员工随机挑选并给你带几只动物。你不知道他选择了哪种动物。你叫他们说话。有的是“吠”,有的是“喵”。

重要!狗可以取,猫不能。如果你确实知道你已经选择了一只狗,它应该能够立即取(例如,从动物到狗)。

如何实现这种逻辑?(最好没有助推::任何)

下面是一个部分工作的示例:http://ideone.com/kR4788

代码语言:javascript
复制
#include <iostream>
#include <map>
using namespace std;

class Animal {};

class Shelter {
    private:
        std::map<int, Animal*> animals;
    public:
        void Add(Animal* animal) {
            animals[animals.size()] = animal;
        };
        Animal* Select(int index) {
            return animals[index];
        }
};

class Dog: public Animal {
    public:
        void Speak() { cout << "bark" << endl; }
        void Fetch() {}
};

class Cat: public Animal {
    public:
        void Speak() { cout << "meow" << endl; }
};

Shelter shelter;

int main() {
    shelter.Add(new Cat());
    shelter.Add(new Dog());

    // I'd like to make it work like this
    //
    // shelter.Select(0)->Speak(); /* meow */
    // shelter.Select(1)->Speak(); /* bark */
    //
    // Like below but without upcasting to given animal

    ((Cat*) shelter.Select(0))->Speak();
    ((Dog*) shelter.Select(1))->Speak();

    // I know under index 1 is a Dog so it can fetch!
    //
    // shelter.Select(1)->Fetch(); /* no segfault */
    //
    // Like below but without upcasting to given animal
    ((Dog*) shelter.Select(1))->Fetch();


    return 0;
}
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2014-04-02 10:16:08

根据要求,我把我的评论作为答复。完整的源代码在艾德龙

在课堂上动物:

代码语言:javascript
复制
class Animal {
  public:
    virtual void Speak() const = 0;
    virtual void Fetch() const { cout << "This animal can't fetch" << endl;};

    virtual ~Animal(){ }
};

需要虚拟析构函数来确保为从基类派生的对象调用正确的析构函数。如果没有虚拟析构函数,则只调用基类析构函数,而不调用派生对象的析构函数。

在狗里:

代码语言:javascript
复制
void Fetch() const { cout << "fetch" << endl; }

主要是:

代码语言:javascript
复制
shelter.Select(0)->Speak();
shelter.Select(1)->Speak();

shelter.Select(0)->Fetch();
shelter.Select(1)->Fetch();
票数 0
EN

Stack Overflow用户

发布于 2014-04-02 09:51:43

编辑:

您可以尝试使用dynamic_castAnimal对象转换为Dog,然后调用fetch方法:

代码语言:javascript
复制
Dog *foo = dynamic_cast<Dog*>(shelter.Select(1));
if (foo) {
  foo->Fetch();
}

如果dynamic_cast失败,它将返回null,因此在使用对象之前确保检查对象是否不是null。有关dynamic_cast的更多信息,请查看这里

您可以向您的虚拟接口添加一个Animal函数:

代码语言:javascript
复制
class Animal {
  public:
    virtual void speak();
};

另外,在一个不相关的注意事项上,您的speak方法似乎没有修改对象,所以您应该考虑将它们作为const

代码语言:javascript
复制
class Animal {
  public:
    virtual void speak() const;
};

您可以找到关于const-正确性这里的更多信息。

票数 1
EN

Stack Overflow用户

发布于 2014-04-02 09:57:14

正如Aliou注意到的那样,speak应该在Animal中声明为virtual,否则层次结构是无用的,或者,换句话说,不存在多态性。

使用Animal测试Dog是否是Dog(同时进行上播)是一个需要考虑的选项。不漂亮,但很管用。

代码语言:javascript
复制
Dog *dog = dynamic_cast<Dog*> shelter.Select(1);
if (dog) dog->Fetch();

(指向指针的dynamic_cast从不抛出,就像其他人建议的那样.)

另一种解决方案是在virtual Fetch中定义Animal,可能是NOP ({}),所以您不必在不提取的动物中定义它。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/22807551

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档