当我只知道成员变量的值时,如何访问 C++ 类的特定实例? [已关闭]

问题描述 投票:0回答:1

作为一个业余爱好项目,我希望改进开源运输游戏Simutrans Extended中的调试设施。

在游戏中,车队(公共汽车、火车等)是

convoy_t
类的实例。他们有一个成员变量
uint ID
。每次处理一个车队时,网络代码都会将其
ID
的值添加到总数中。如果客户端和服务器的总数存在差异,它们就会不同步。计算客户端和服务器总数之间的差异可以得出导致不同步的车队的 ID 号(我们称之为
uint problematic_convoy
)。我想仅使用
problematic_convoy
来识别该 convoy 对象(这样我就可以将其传递给各种其他函数以获取更多信息等)。

正如您所期望的,

convoy_t
有一个公共成员函数
get_ID()
,因此一旦我们有一个实例或指向它的指针,我们就可以检查任何实例的
ID
。我考虑循环遍历类的所有实例来检查是否
get.ID() == problematic_convoy
。但我只了解了
self.getID()
*mypointer.getID()
形式的示例;在这种情况下,我还没有可以与
operator.
一起使用的对象或指针。我怀疑我完全不知道解决整个问题的正确方法。

由于这是一个学习者的问题,我欢迎一个指向现有答案的“指针”(双关语),即我需要研究的 C++ 领域来做到这一点,例如相关语言功能的名称或相关LearnCPP.com 上的课程(我正在学习)。

我发现了这个类似的问题,但它是针对 Objective-C 的,而不是针对 C++ 的。答案推荐了工厂和单例模式,但它们似乎是用于实例化新对象,而不是访问大型代码库中的现有对象,并且单例模式似乎是有争议的。

编辑: 感谢 @drescherjm 和 @Ted Lyngmo 的有用评论,我想我现在知道了正确的方向。有一个类

convoihandle_t
,基于模板 quickstone_t,这是一个墓碑表。它看起来不像我以前遇到过的任何数组,但根据您的评论,它一定是一个我可以迭代的数组。那一定是我需要研究和理解的代码。谢谢!

c++ class instance
1个回答
0
投票

一般来说,没有办法通过了解 C++ 类实例来找到 其数据成员之一的值,有两个原因:

  • 数据成员值可能不唯一。

  • 即使是这样,也没有语言或语言提供任何便利 用于在类的所有实例中搜索的标准库。

解决这个问题最典型的方法是构建某种 预先包含您要搜索的所有实例的容器 通过。

一种方法:使用 std::map

例如,如果存在一个创建对象的现有函数:

convoy_t *makeConvoy(...)
{
  convoy_t *convoy = new convoy_t(...);

  // maybe do other things

  return convoy;
}

然后您可以修改此代码以通过以下方式跟踪所有对象 首先创建一个容器,例如

std::map
。为了 为了简单起见,我们将在文件范围内实现它,但可能有更好的地方 将其放入实际程序中:

#include <map>               // std::map
#include <utility>           // std::make_pair

// Map from convoy ID to a pointer to the instance.
std::map< int, convoy_t* > convoyMap;

然后,在

makeConvoy
中的
return
之前,添加插入它的代码 进入地图:

  // This uses the "traditional" insertion syntax.  See notes below.
  convoyMap.insert(std::make_pair(
    convoy->getID(),         // key
    convoy));                // value

最后,当你有了ID并想要它的车队时,在 使用

at
绘制地图 方法:

  convoy_t *convoy = convoyMap.at(ID);

一些注意事项:

  • 您需要确保 ID 是唯一的。如果不是,那么当你尝试时 要将具有相同 ID 的第二个对象添加到地图中,

    insert
    调用不会执行任何操作(有关详细信息,请参阅链接参考)。

  • at
    方法会抛出
    std::out_of_range
    如果未找到 ID。你应该编写一个异常处理程序来处理 有这种可能性。

  • insert
    的调用也可以使用更紧凑的方式编写 利用初始化列表的符号,引入 C++11:
    convoyMap.insert({convoy->getID(), convoy});

  • 如果一个物体是 已删除, 那么它也必须从地图上删除。否则,指针在 地图将“悬挂”,这意味着它指向记忆 随后被重新用于其他目的,导致各种 问题。

  • 如果对象的 ID 发生更改,则必须将其从地图中删除并使用新 ID 重新插入。映射本身并不知道用作键的 ID 与数据成员值相同。

完整示例

这是演示上述技术的完整程序:

// convoy.cc
// Demonstrate finding objects by ID.

#include <cassert>           // assert
#include <map>               // std::map
#include <utility>           // std::make_pair


int nextConvoyID = 1;


class convoy_t {
public:      // instance data
  int m_id;
  int m_otherData;

public:      // methods
  convoy_t(int id, int otherData)
    : m_id(id), m_otherData(otherData) {}

  int getID() const { return m_id; }
};


// Map from convoy ID to a pointer to the instance.
std::map< int, convoy_t* > convoyMap;


convoy_t *makeConvoy(int otherData)
{
  int id = nextConvoyID++;
  convoy_t *convoy = new convoy_t(id, otherData);

  if (false) {
    // Traditional syntax.
    convoyMap.insert(std::make_pair(
      convoy->getID(),         // key
      convoy));                // value
  }
  else {
    // More compact notation using an initializer list.
    convoyMap.insert({convoy->getID(), convoy});
  }

  return convoy;
}


int main()
{
  // Make some convoys.
  convoy_t *c1 = makeConvoy(11);
  convoy_t *c2 = makeConvoy(12);
  convoy_t *c3 = makeConvoy(13);

  // Get one of the IDs.
  int id = c2->getID();

  // Amnesia strikes!  Where did 'id' come from?
  convoy_t *convoy = convoyMap.at(id);

  // Ah, there it is.
  assert(convoy == c2);

  return 0;
}


// EOF

可能已经有一个容器可供您使用

您说您在 Simutrans Extended 工作。我什么都不知道 关于它,但正如评论中指出的,它似乎有一个

world
可以是的对象 穿越

// loop through all convoys
for (vector_tpl<convoihandle_t>::const_iterator i = world->convoys().begin(), end = world->convoys().end(); i != end; i++) 
{
  current_convoy = *i;
  // only consider lineless convoys which support this compartment's goods catetory
  if ( !current_convoy->get_line().is_bound() && current_convoy->get_goods_catg_index().is_contained(catg) )
  {
    temp_linkage.convoy = current_convoy;
    linkages->append(temp_linkage);
    transport_index_map[ 65536u + current_convoy.get_id() ] = linkages->get_count();
  }
}

循环遍历所有车队以找到具有特定 ID 的车队是 效率不是很高,但可能足以满足您正在做的事情。可能还存在已经存在的运输地图;就像我说的,我不知道那个程序。

© www.soinside.com 2019 - 2024. All rights reserved.