如何在二维数组中引用对象?

3

我读到可以通过以下代码声明一个对象数组:

Enemy * d = new Enemy[2];

但是当我尝试创建一个二维数组时,出现了无法初始化的错误。我也尝试过这样做:

Enemy *enemies[6][2];

但我不确定如何引用数组中的每个对象,以及如何将该引用传递给函数。

4个回答

10

为了创建一个锯齿数组,您需要使用指向指针的指针。

Enemy** d = new Enemy*[6];
for (size_t i = 0; i < 6; ++i)
    d[i] = new Enemy[2];
如果你打算创建一个固定大小的数组,你可以像创建普通数组一样创建它。
Enemy enemies[6][2];

然后你只需要使用两个索引来引用它们。

enemies[2][1].roar();

注意:你会发现多维数组往往会比它们值得的头疼得多。保持单个维度数组更加清晰,只需基于行数和列数进行索引即可。

Enemy* enemies = new Enemy[rows * cols];

Enemy* getEnemy(size_t row, size_t col)
{
    return enemies + (row * cols + col);
}

如果我在主函数中创建这些数组,我该如何将它们传递给函数呢? - Bartlomiej Lewandowski
如果你想要简单的方式,你可以直接将它作为 foo(Enemy** array) 传递。还有一种更复杂的方式,允许你维护静态大小数组的类型信息,但我不会担心这个问题 - 像上面的 foo() 中的指向指针的指针就足够了。 - John Humphreys
这取决于您如何创建数组以及如何处理它。如果您创建了一个交错数组,您需要将其作为 Enemy** 传递,并传递两个维度。如果您创建了一个固定大小的数组,则需要声明至少一个维度。void kill(Enemy enemies[6][]); - TheBuzzSaw
所有这些单独的分配会影响缓存局部性。此外,将它们显式化也意味着内存难以清除。 - celtschk
@celtschk 你可以分配一个单一的块,然后使用放置 new 来构造对象... 虽然绝对不简单。 - Michael Price
显示剩余2条评论

3
如果你真的想把一个2D数组分配到堆上,这是实现方法:
Enemy (*enemies)[2] = new Enemy[6][2];

但是没有间接操作就简单得多:

Enemy enemies[6][2];

1

对于C++,您应该使用std::vector而不是C数组。

  std::vector<std::vector<Enemy> > d(6);
  for (size_t i = 0; i < 6; ++i)
       d[i].resize(2);

  //now d is ready to use
  d[1][2];

1
然而,使用该方法时,您的元素在内存中不是连续的(因为内部向量都使用单独的分配),并且每个访问都包含额外的重定向。这两者可能会由于缓存局部性(或者更确切地说,缺乏缓存局部性)而损害您的性能。相反,使用一个具有2 * 6个元素的单个向量,并使用索引算术访问它(最好封装在一个漂亮的类中)。 - celtschk
是的,实际上我不支持这个答案。你应该只在需要自动内存增长的非常特殊的情况下使用向量。否则,最好不要使用STL的所有多余的东西来仅仅分配一个数组。 - TheBuzzSaw

0

你会做

Enemy (*enemies)[2] = new Enemy[6][2];

也就是说,这是一个指向2个敌人数组的指针。 请注意,只有第一层数组可以成为指针,并且在运行时确定。

还要注意,您的第二个定义创建了一个包含6*2个敌人指针的数组。假设您已经初始化了它们所有,您可以访问它们如*enemies[j][k],或者如果每个指针本身指向一个数组,则为enemies[j][k][l]

请注意,如果您想要同时确定两个索引,您应该分配一个大数组并使用索引算术:

Enemy* enemies = new Enemy[6*2]; // 访问元素(j,k) enemy[6*j+k].fight();

当然,通常最好使用vector<Enemy>,除非您的类Enemy不适合于向量,例如因为它无法复制(或在C++11中移动)。此外,在进行多维数组时,理想情况下应该将数组和索引逻辑封装在一个类中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接