是否可以同时初始化两个需要指向彼此的类?

时间:2012-11-29 12:21:56

标签: c++ class

我正在制作蛇游戏。我有两个班级,snakefood。当我调用snake->move()时,它需要检查没有冲突,为此目的,它需要知道food的位置是什么,因此需要指向food的指针。 food有一个函数可以将它移动到一个新的随机位置move->setNewPosition(),它需要知道snake的位置,以便它在移动时不会与蛇发生碰撞。为此,它需要一个指向snake

的指针

因此,对于这两个类,我需要提供一个指向另一个必须初始化的类的指针。但要初始化其他类我需要初始化其他类等等。有没有办法初始化两个需要指向彼此的类?

如果没有,那么构建我的程序会有什么更好的方法可以让我检查另一个类的坐标?

6 个答案:

答案 0 :(得分:2)

如果我没有误解你,请在游戏循环开始之前创建调用的init函数:

void initSnake()
{
   auto snake = new Snake();
   auto food = new Food();   
   snake->setFood(food);
   food->setSnake(snake);
}

答案 1 :(得分:1)

您可以为它们定义一个基类,它们具有以下方法:

virtual void setPosition(const int x, const int y)
virtual void getPosition(int &x, int &y) const

Snake也应该使用它们,如果需要,只需覆盖它们。现在,如果您将另一个对象作为类型为setPosition的参数提供,则这两个类可以直接相互调用getPositionBase

另一种方式是;在main() - 函数中,或在您定义蛇的任何地方:

int main()
{
    Snake* s = new Snake;
    Food* f = new Food;
    Snake->setLocation(0,0); // Wherever you want the snake to start from
}

每当你创建一个新的食物时,给它蛇的位置:f->setRandomLocation(snake->getLocation())其中参数将是不放置它的坐标。

答案 2 :(得分:1)

当他们的动作功能被调用时,他们只需要设施来找到其他蛇和食物的位置。在初始化时没有必要知道它们的存在!

因此,您可以拥有一系列蛇和食物集合,并将这些集合的参考传递给任何新创建的蛇和食物。首先创建这些集合。

你可以通过另一个类来做到这一点,也许也可以作为一个工厂。

class GameManager;

class Snake
{
    friend class GameManager;

    public:
        int getX() { return _x; }
        int getY() { return _y; }

        void setPosition(int x, y) { /* ... */ }

    private: 
        Snake(GameManager* manager, int x, int y) : _manager(manager), _x(x), _y(y) {}

        GameManager* _manager;
        int _x, _y;
};

class GameManager
{
    public: 
        const std::vector<Snake*>& Snakes() { return _snakes; }

        Snake* SpawnSnake(int x, int y) 
        {
            Snake* newSnake = new Snake(this, x, y);
            snakes.push_back(newSnake);
            return snake;
        }

    private:
        std::vector<Snake*> _snakes;
};

(只是一个例子。未对代码进行测试以确定它是否实际编译.E&amp; OE)

GameManager确保在蛇矢量中找到所有创建的蛇,因为Snake构造函数是私有的。每条蛇都可以调用_manager.Snakes()来获得一个包含游戏中所有其他蛇的向量,然后它可以单独查询它们的位置。这很容易推广到支持食品。

这比其他答案中建议的“构造初始化”模式有一个小优势,因为它确保当你得到一个新的Snake对象时,它实际上已经可以使用......这个例子不是相当RAII,但它需要最少的努力才能使其合理地例外安全。

答案 3 :(得分:0)

另一种选择是拥有一个Manager课程,他们都会发送请求,这样会更有意义(但不能解决您的特定问题)。

尽管如此,如果您有class Aclass B,并且每个人都需要另一个,您可以执行以下操作:

A *a = new A;
B *b = new B;
// check a and b to make sure they are not NULL
a->set_b(b);
b->set_a(a);

答案 4 :(得分:0)

Mmn,不确定你的游戏是如何运作的,但我认为会有很多食物对象?

也许一个想法就是创建一个Collision课程,接受一个Snake播放器并将所有食物玩家存储在游戏中。 所以Collision构造函数可能看起来像这样

Collison(Snake &snake, Vector<Food*> &foods)
{

}

Collision类也会有一个碰撞更新循环,你在代码中的某个地方调用。这个循环会检查蛇对象是否与食物对象碰撞..你可以做任何你想做的事情。去掉食物从foods vector改变食物位置,无论如何。

collison.UpdateCollisions() ; 

答案 5 :(得分:0)

我建议打破循环依赖,而不是锤击它:使两个移动函数都将环境(即它可以碰撞的事物列表)作为参数。