繁体   English   中英

遍历 shared_ptr 的向量

[英]Iterate through a vector of shared_ptr

我有两个类(羊和狼)源自一个(动物)。 我创建了一个这样的共享指针向量:

std::vector<std::shared_ptr<animal>> animals;

for (int i = 0; i < n_sheep; i++) {
    auto my_sheep = std::make_shared<sheep>();
    animals.push_back(std::move(my_sheep));
  }

  for (int i = 0; i < n_wolf; i++) {
    auto my_wolf = std::make_shared<wolf>();
    animals.push_back(std::move(my_wolf));
  }

遍历此向量并了解这些 smart_ptr 之间区别的最佳方法是什么?

像这样的东西:

for (int i = 0; i < animals.size(); i++) {
    if (animals[i] == sheep)
        //TODO
    if (animals[i] == wolf)
        //TODO

谢谢你们。

“最好的”取决于几件事。 例如,谁控制 class Animal 的定义?

我真的很喜欢做类似的事情:

class Animal
{
public:
  virtual std::string what() = 0;
};

class Wolf : public Animal
{
public:
  virtual std::string what() { return "wolf"; }
};
class Sheep : public Animal
{
public:
  virtual std::string what() { return "sheep"; }
};

您还可以定义一个枚举来摆脱比较字符串的需要,但是当然,这意味着您将失去在不编辑该枚举的情况下添加更多动物的能力。

如果您无法更改Animal ,您可以执行以下操作:

if( typeid(*animals[i]) == typeid(Wolf) )
{
  // do wolfy things
}
else if( typeid(*animals[i]) == typeid(Sheep) )
{
  // do sheepish things
}

您可以使用dynamic_pointer_cast将一个衍生 class 与另一个衍生。 这可能不是最好的方法,但即使您无法向基础添加新的虚拟方法,它也可以工作。

for (auto animal: animals){
  auto p = std::dynamic_pointer_cast<wolf>(animal);
  if(p) std::cout << "wolf"; // p will be null if it is not wolf
  else std::cout << "sheep"; // if you have only two animals,
                             // otherwise you need to cast to sheep
                             // to check if it is actually sheep
}

作为@v010dya 方法的一种变体(假设您可以自由修改Animal),我会(如前所述)使用枚举。 如果您选择十六进制值,则可以使用位运算符,这使得比较更简单(尽管依赖于隐式转换为 int)。

但是,我会将此逻辑拆分为“关系”class。 问题是您真的不想用派生类的知识污染 Animal,但您确实需要有一种方法让不同的派生类进行交互。

在这里,我使用 Menagarie 作为 class 来控制不同动物之间的关系。 这样一来,Wolf 就不需要知道关于 Sheep 的任何事情,只需要知道它是一种可以吃的动物。 您可以将此模式用于不同类型动物之间的其他交互。

#include <iostream>

//Fwd definition of Animal
class Animal;

//This class controls the relationships between animals
class Menagerie
{
public:
    enum Type { NONE = 0x00, SHEEP = 0x01, GOAT = 0x02, WOLF = 0x04, LION = 0x08 };
    //Defines the food chain
    static bool canBeEatenBy(const Animal* pLunch, const Animal* pDiner);
};

class Animal
{
public:
    virtual Menagerie::Type type() const = 0;
    virtual void DoSomething() = 0;
  
    virtual ~Animal() {}
};

class Sheep : public Animal
{
public:
    Menagerie::Type type() const override { return Menagerie::SHEEP; }

    void DoSomething() override
    {
        //Do Sheep-specific things
    }
};

class Wolf : public Animal
{
public:
    Menagerie::Type type() const override { return Menagerie::WOLF; }

    void DoSomething() override
    {
        //Do Wolf-specific things
    }
};

//This defines the logic of who-eats-who
//Can be moved to implementation file, so you can 
//change the logic in one place with minimal recompilation
bool Menagerie::canBeEatenBy(const Animal* pLunch, const Animal* pDiner)
{
    switch (pLunch->type())
    {
    case SHEEP:
        return pDiner->type() & (WOLF | LION);
    case GOAT:
        return pDiner->type() & (WOLF | LION);
    case WOLF:
        return pDiner->type() & LION;
    case LION:
        return false;
    default:
        return false;
    }
}

int main() 
{
    Wolf w;
    Sheep s;

    if (Menagerie::canBeEatenBy(&s, &w))
    {
        std::cout << "Lunchtime for Wolf!\n";
    }

    if (Menagerie::canBeEatenBy(&w, &s))
    {
        std::cout << "Lunchtime for Sheep!\n";
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM