C++生态系统模拟器(继承)

C++ ecosystem simulator (inheritance)

我是用 C++ 开发生态系统的初学者。它是这样工作的:

我的网格上有 PLANTS(此处未显示)和 ANIMALS

如果某物是 ANIMAL,它要么是 CARNIVORE,要么是 HERBIVORE

我创建了这个层次结构:

class ANIMAL
{
private:
    int a_CUR_food_lvl; 
    const int a_MAX_food_lvl; 
    const int a_hunger_rate; 

public:

    ANIMAL(int curr, int max, int rate)
        : a_CUR_food_lvl(curr),
        a_MAX_food_lvl(max),
        a_hunger_rate(rate)
    {}

     virtual ~ANIMAL()
     {
        delete this;
     }

    virtual void Move() = 0;
    virtual void Eat() = 0;
    virtual void Evade() = 0;
    virtual void Reproduce() = 0;
    virtual void Die() = 0;
    virtual void Age() = 0;

    virtual int get_a_CUR_food_lvl() { return a_CUR_food_lvl; };
    virtual int get_a_MAX_food_lvl() { return a_MAX_food_lvl; };
    virtual int get_a_hunger_rate() { return a_hunger_rate; };
}; //end ANIMAL class


//#################################################################
class CARNIVORE : public ANIMAL
{
public:

    class WOLF : public ANIMAL
    {
        WOLF()
            : ANIMAL(150, 200, 2)
        {}
    };

    class CHEETAH : public ANIMAL
    {
        CHEETAH()
            : ANIMAL(75, 125, 5)
        {}
    };
}; //end CARNIVORE class


//#################################################################
class HERBIVORE : public ANIMAL
{
public:


    class RABBIT : public ANIMAL
    {
        RABBIT()
            : ANIMAL(150, 200, 2)
        {}
    };


    class SQUIRREL : public ANIMAL
    {
        SQUIRREL()
            : ANIMAL(150, 200, 2)
        {}
    };
}; //end HERBIVORE class

我的问题:

稍后,我想使用 dynamic_cast 查看是否允许一只动物吃另一只动物。具体来说,如果 ACARNIVORE 并且 BHERBIVOREAnimal A 只允许吃动物 B

像我那样嵌套 类 是否允许我在以后的编程中检查对象的类型?我现在不想认为这是正确的并且不得不改变它。

或者如果有比 dynamic_cast(布尔值 is_carnivore?)更好的方法,我应该改用它吗?我的目标是最易读和最佳的 OOP 实践

如果我是对的,你可以做一些简单的事情,比如让每只动物在生态系统中都有自己的水平。像这样:

class Animal {
Animal(int curr, int max, int rate, int level)...

}

以后再做,让动物们只能吃低等级的动物。

类似于:

if(animalA.level < animalB.level){
    ...
}else{
    ...
}

关于巢穴,但我不确定那是否合法。从来没有尝试过那样做,我可能不会。

您的嵌套 类 根本不代表您想要的。不要进一步考虑此构造来解决您的问题。相反:

  • WOLF 和 CHEETAH 应该继承自 CARNIVORE
  • SQUIRREL 和 RABBIT 应该继承 HERBIVORE

然后有几种方法可以查看动物 *a 是否可以吃掉另一只动物 *b。正如您所建议的,最简单的方法是 dynamic_cast:

ANIMAL *a, *b; 
...
if (dynamic_cast<CARNIVORE*>(a) && dynamic_cast<HERBIVORE*>(b)) {
     // *a can eat *b
}

但这不是最佳的 OOP 实践。我不知道你所有的限制和要求,但如果你想成为最先进的并且能够编码更复杂的规则(比如主角的力量和健康,某些物种的例外等)你可能是有兴趣实施某种 double dispatch (such as discussed here

您已经有了部分答案,virtual函数就是您所需要的。您将在基础 class 中定义一个名为 isCarnivore()isHerbivore() 的虚函数,然后在派生的 class 中创建定义到 return true 或 false对象是什么类型。

示例:

class ANIMAL {
public:
    virtual bool isHerbivore() = 0; //overload this in your derived class to determine if it is a carnivore
    bool isCarnivore() {
        return !isHerbivore(); // if its an herbivore it cannot be a carnivore and vice versa
    }
};

class CARNIVORE : public ANIMAL {
    virtual bool isHerbivore() override {
        return false;
    }
};

class HERBIVORE : public ANIMAL {
    virtual bool isHerbivore() override {
        return true;
    }
};

在这里您可以找到一个 运行 我建议的两级继承示例(我看到它已作为答案同时发布):

#include <iostream>

struct Animal
{
    virtual ~Animal() {};
};
struct Carnivore : public Animal {};
struct Herbivore : public Animal {};
struct Wolf      : public Carnivore {};
struct Cheetah   : public Carnivore {};
struct Squirrel  : public Herbivore {};
struct Rabbit    : public Herbivore {};

bool can_eat(Animal* predator, Animal* prey)
{
    return ( dynamic_cast<Carnivore*>(predator) && dynamic_cast<Herbivore*>(prey) );
}

int main()
{
    Animal* wolf   = new Wolf();
    Animal* rabbit = new Rabbit();

    std::cout << "Wolf eats rabbit = " << can_eat(wolf, rabbit) << std::endl;
    std::cout << "Rabbit eats wolf = " << can_eat(rabbit, wolf) << std::endl;

    return 0;
}

您可以简单地向表示食物链层次结构的基础 class 添加一个属性。例如:

#include <iostream>
class Animal
{
    private:
        int a_CUR_food_lvl; 
        int food_chain_level;
        const int a_MAX_food_lvl; 
        const int a_hunger_rate; 

   public:
        Animal(int curr, int max, int rate, int food_chain)
        : a_CUR_food_lvl(curr), a_MAX_food_lvl(max),
        a_hunger_rate(rate), food_chain_level(food_chain) {}

        bool canEat(Animal& theAnimal) const
        { return food_chain_level > theAnimal.food_chain_level; } 
//...
}; 

class Carnivore : public Animal
{
   public:
        Carnivore(int curr, int max, int rate) : Animal(curr, max, rate, 2) {}
};

class Herbivore : public Animal
{
   public:
        Herbivore(int curr, int max, int rate) : Animal(curr, max, rate, 1) {}
};

class Insect : public Animal
{
   public:
        Insect(int curr, int max, int rate) : Animal(curr, max, rate, 0) {}
};

Carnivore Wolf(150, 200, 2);
Carnivore Cheetah(75,125,2);
Herbivore Squirrel(150,200,2);

using namespace std;

int main()
{
   cout << (Wolf.canEat(Squirrel)?"true":"false") << endl;
   cout << (Squirrel.canEat(Cheetah)?"true":"false") << endl;
}

Live Example

请注意,我使用了一个简单的整数,但很可能是一种更复杂的方法(可能将大小作为动物可以吃掉另一只动物的另一个决定因素)。正如我的评论所暗示的那样,有些小型食肉动物绝不能吃大型食草动物。