如何在运行时正确地将指向派生 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_cast
、reinterpret_cast
、dynamic_cast
和 const_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++ 模板系统和类型推导机制 运行。如果你想在 运行 时间处理动态类型系统(即用户输入决定使用的类型),你必须使用类似工厂方法的东西。
但是,如果有更好的方法,可能值得考虑。
我目前正在编写一些需要允许在运行时实例化半任意 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_cast
、reinterpret_cast
、dynamic_cast
和 const_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++ 模板系统和类型推导机制 运行。如果你想在 运行 时间处理动态类型系统(即用户输入决定使用的类型),你必须使用类似工厂方法的东西。
但是,如果有更好的方法,可能值得考虑。