类指针与引用

Class Pointers vs Reference

本文关键字:引用 指针      更新时间:2023-10-16

我了解指针和引用的基础知识,但我遇到的最大问题是决定何时应该使用它们(以及使用哪个)。我将给出的主要示例是一个基本游戏。假设设置如下所示:

  • 新世界
    • 照相机
    • 地图
世界

是一个指针,因为每次游戏开始新的存档或加载现有存档时,它都会删除世界并加载一个新世界。但是在世界内部,相机和地图应该只存在一个,而且只存在于世界期间。如果世界被毁灭了,那么显然他们也应该毁灭。然而。。假设 Map 需要访问相机(但其他对象也是如此),相机应该通过引用传递到 Map 中还是作为指针传递,或者?例如,如果它应该是通过引用,它应该是:

map = Map(&camera);
(inside map class) Map(Camera camera) {...}

或者更像:

map = Map(camera);
(inside map class) Map(Camera &camera) {...}

另外,假设地图包含一个名为网格的图块的 2D 矢量。像这样:

std::vector< std::vector< Tile > > > grid;

现在假设我有一个 PathFinder 类,它需要传入该网格。它需要直接编辑图块以更改 f、g 等值(用于寻路)。那个2D向量应该只是Tile的普通2D向量,整个东西都是通过参考PathFinder传递的吗?还是应该是平铺指针的 2D 矢量?

此外,NPC和玩家将有一个当前图块,这是他们当前所在的图块。他们需要有一个指向该磁贴的引用或指针,以便他们也可以通过 NPC/Player 类中的类似内容将自己设置为该磁贴上的占用者:

currentTile = tile;
currentTile->SetOccupant(this);

另一个问题出现在我销毁该网格以加载新地图时,我如何轻松处理确保没有任何东西指向不再存在的瓷砖。我是否只需要遍历这些类并将当前磁贴设置为 NULL?

这就是我开始真正被这些东西弄糊涂的地方。任何帮助都值得赞赏,因为我显然很菜鸟。@_@;很抱歉,如果这与游戏主题无关。如果需要将其移动到不同的堆栈交换,请告诉我或移动它(如果可以的话)。>_<</p>

考虑 Map 类。您可以通过引用或作为指针传入摄像机。真的无所谓。重要的是传入的相机会发生什么。是否要将其分配给作为摄像机*的成员?否则,在构造函数中设置 Camera 将不会完成太多工作。每次调用需要相机的地图时,都必须提供相机指针/参考。

对于存储 Tile 对象,单个维度 std::vector<> 就可以了。通过使用一些简单的数学运算,可以轻松遍历此磁贴网格。在里面嵌套另一个向量只会导致不必要的开销。下面是执行此操作的示例算法:

std::vector<Tile> tiles = makeTiles();
for (int y=0; y<mapHeight; y++)
{
   for (int x=0; x<mapWidth; x++)
   {
      Tile tile = tiles.at(x + y*mapWidth);
      tile.doSomethingWithTile();
   }
}

决定如何将切片数据从地图获取到 PathFinder 实际上取决于您希望如何保护地图数据。通过提供对所有磁贴数据的引用,实质上是使其公开访问。由于 PathFinder 需要编辑单个图块,而不是整个图块数组本身,因此更好的方法是使用如下方法:

Tile* Map::AccessTile(int tx, int ty);

这样,整个图块数据向量就不会暴露出来,但PathFinder将能够获得它所需要的东西。此外,Map::AccessTile() 可以设为私有,PathFinder 声明为 Map 的朋友。另一种方法是提供像 Map::SetTileF(int tx, int ty, float f) 这样的方法。不过,这可能很乏味。

对于NPC和玩家,可以使用类似的解决方案。他们实际上不需要对他们所在的磁贴具有直接写入访问权限。添加一个类似于 Map::SetTileOccupant(Entity *entity) 和相应的 Map::GetTileOccupant() 这样的方法。

现在您对删除对象的担忧。您应该查看C++提供的一些模拟指针(特别是std::shared_ptr<>和std::weak_ptr<>)。对这些的快速解释是shared_ptr是一个"拥有"对象的指针,weak_ptr知道在哪里访问该对象,但实际上并不"拥有"该对象。

使用这些模拟指针,您可以执行以下操作:

//prototype for setWorld
//note that shared_ptr<> casts to weak_ptr<> nicely
Camera::setWorld(std::weak_ptr<World> world);
//setup the camera and world
std::shared_ptr<World> world(new World);
Camera camera;
camera.setWorld(world);

使用上面的代码,相机有一个指向世界的指针。如果由于某种原因删除了世界,相机可以通过以下方法解决此问题:

bool Camera::worldIsValid()
{
   return (this->mWorld.expired() == false);
}

此外,您将摄像机封装在一个世界中,这可能是您不需要做的事情。相反,相机可以是独立的,只要需要有关它的信息或世界中包含的地图,它就会引用一个世界。