C++ 在运行时获取具有 ID 的对象

C++ Getting objects with IDs at runtime

本文关键字:ID 对象 运行时 获取 C++      更新时间:2023-10-16

假设我们有以下对象:

struct A{
static const int ID = 1;
};
struct B{
static const int ID = 2;
};
struct C{
static const int ID = 3;
};
struct D{
static const int ID = 4;
};
struct Collection{
std::vector<A> o1;
std::vector<B> o2;
std::vector<C> o3;
std::vector<D> o4;
};
Collection collection;

我想做的是获取对Collection的一些vector的引用。应该有三种不同的方法来检索这些:

  1. vector类型,例如collection.get<A>();

  2. 编译时由 ID 定义,由vector持有的每个对象定义,例如collection.get<4>();

  3. 按运行时的 ID,例如collection.get(id);

案例1 很容易,因为它可以通过T::ID转换为案例 2。案例 2 可以通过模板专用化来实现(尽管如果我有很多对象,它看起来很丑(。 案例3制造了很多麻烦。如果没有一些巨大的ifswitch语句,它几乎是不可能的,更不用说推断返回类型了。

我的问题是:

  • 有没有办法让案例 2 更优雅?
  • 我应该如何实现案例 3?

有些事情你可以做,有些事情你永远做不到。你所要求的不是那么简单,需要努力工作。

1 和 2 很困难,但可以实现。首先,创建所有类型 ID 的静态映射,然后使用静态结果选择类型。

现在3... 嗯...很抱歉告诉你这是不可能的!提供一个反例来证明我所说的:你永远不能创建一个在运行时选择返回类型的函数。但。。。

你可以做一些事情,这基本上是LLVM人员为摆脱dynamic_cast所做的,但它的代码太多了。

首先,将一个基抽象类装为例,并使所有这些类都从它派生,并使其包含 ID:

struct Base{
virtual int getClassID() = 0;
static Base* CreateObject(int ID) //consider using shared_ptr here
{
switch(ID) {
case A::ID:
return new A;
}            
case B::ID:
return new B;
default:
return nullptr;
}
//...
}
}
struct A : public Base {
static const int ID = 1;
int getClassID() override {
return ID;
}
};
struct B : public Base {
static const int ID = 2;
int getClassID() override {
return ID;
}
};
struct C : public Base {
static const int ID = 3;
int getClassID() override {
return ID;
}
};
struct D : public Base {
static const int ID = 4;
int getClassID() override {
return ID;
}
};

现在,要实例化一个新类,请使用基类。

Base* c = Base::CreateObject(3); //object of C

现在,最后,您创建您的魔术施法运算符:

template <typename T>
T* MyMagicCast(Base* obj)
{
if(obj->getClassID() ISVALID) //Then use the ID to make sure that T matches the ID
{
return static_cast<T*>(obj);
}
else
{
return nullptr;
}
}

这将为您完成运行时的工作。使用此方法,您的优势在于可以通过调用 base + 不使用任何 RTTI 来完成所有类型的操作。现在,仅当您需要特定于您拥有的类型之一(A,B,C,D(时,才使用MyMagicCast()转换为其类型。

PS:代码在我的头顶上,所以可能有轻微的错别字/错误。