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

标签 c++ templates runtime

假设我们有以下对象:

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;

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

  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 很难,但可以实现。一、create a static map of all type-IDs , 然后 use the static result to choose the type .

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

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

首先,case一个基本抽象类,并使所有这些类都派生自它,并使其包含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:代码不在我的脑海中,所以可能会有轻微的错别字/错误。

关于C++ 在运行时获取带有 ID 的对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45238202/

相关文章:

c++ - opencv-4.1.2 构建后要清理哪些文件和文件夹?

c++ - 我如何将 uint32_t 转换为 char* 类型

类方法 : partial specialization if parameter is enum 上的 C++ 类型特征

IIS 未使用正确的 .NET Core 版本 - 如何管理?

c++ - 从 boost::array<char, 100> 中提取字符集

c++ - 带有字符串定界符或两个字符的 fstream

c++ - Pthread 模板参数错误

c++ - 指向在 C++ 中自动返回 'type' 的模板成员的指针?

java - 我可以将类添加到 sun 的 rt.jar 文件吗?

ios - Objective-C 在运行时调用类私有(private)的类方法