如何在运行时正确地将指向派生 class 的 void* 转换为指向基础 class 的 void*

How to correctly cast a void* that points to a derived class to a void* that points to a base class at runtime

我目前正在编写一些需要允许在运行时实例化半任意 c++ classes 的代码,这意味着如果例如用户输入 "Class1",将实例化 Class1 的新实例。

所有这些都必须以 void* 形式存储,因为 classes 不一定共享任何基础 classes(我也想支持原语,但我'我目前没有这样做)

void* 在使用时被转换为正确的类型,但问题在于我也允许它们用作指向基的指针 class。

例如

void* p = new Derived();
((Base*)p)->someVirtualFunction();

我需要一种正确投射到基地的方法。显然,如果我有易于访问的类型,我可以:

void* p = (Base*)(new Derived());
((Base*)p)->someVirtualFunction();

不会有问题。

不过我手头没有那种好用的。

我确实有一个基础设施:

class Type {};

template<typename T>
class TypeImpl : public Type {};

在实际代码中,这些函数有很多与手头问题无关的函数。

我可以访问指向 TypeImpl<Base>Type* 和指向 TypeImpl<Derived>

Type*

我正在尝试找到一种方法来使用这些来正确投射指针 例如

class Type {
    void* cast(Type* type_of_p, void* p)=0;

    template<typename C>
    void* castTo(void* p)=0;
};

template<typename T>
class TypeImpl : public Type {
    void* cast(Type* type_of_p, void* p){
        return type_of_p->castTo<T>(p);
    }

    template<typename C>
    void* castTo(void* p){
        return ((C*) ((T*) p));
    }
};

但是没有虚函数模板,我找不到办法做到这一点。

至于其他解决方案,我最接近的想法可能是索引在 std::type_index 上的函数指针的哈希图的某种哈希图,但我也无法让它工作。

这可能吗?如果可以,我该怎么做?

编辑以希望澄清:

我有一个 void* p 指向 Derived 我需要将它转换为 Base* (例如 void* p = new Derived();

(Base*)p 或任何不使用运行时信息的类型转换都无效,因为 vtable 未对齐。

我需要这样的东西: (Base*)(Derived*)p(或等效的 c++ 转换)但我不知道它是哪个派生的 class。

我不确定是我的措辞很糟糕还是我犯了一些错误,但这是核心问题。

首先,我建议使用 C++ 转换,而不是普通的旧 C 转换,例如 static_castreinterpret_castdynamic_castconst_cast。它们比 C 类型转换更安全,因为它们只做一件事。

既然你提到你有一个指向你试图转换到的 base/derived class 的对象的指针,你可以使用 decltype.

decltype 是一个 C++11 说明符,它产生作为参数传递的变量的类型。

因此,您可以使用类似 reinterpret_cast<decltype(base_pointer)>(value) 的东西。

有关更多信息,请查看以下资源:

https://en.cppreference.com/w/cpp/language/decltype

Cast a value using decltype, is it possible?

When should static_cast, dynamic_cast, const_cast and reinterpret_cast be used?


评论中的讨论指出,最初的问题要求 运行time 方法,而 decltype 是编译时间。尽管如此,以上内容可能是相关的,所以我将添加一些关于 运行时间方法的想法。

编译时的 C++ 模板系统和类型推导机制 运行。如果你想在 运行 时间处理动态类型系统(即用户输入决定使用的类型),你必须使用类似工厂方法的东西。

但是,如果有更好的方法,可能值得考虑。