无法用static_cast实现Base到Derived转换?求非reinterpret_cast替代方案
我们可以使用static_cast将Base*转换为Derived*,但在Base构造函数中执行转换时,由于仅存在Derived的前向声明,类之间的继承关系对编译器不可见,导致转换无法进行。请问除了reinterpret_cast外,是否有其他可行方法实现该转换?
示例代码
struct Derived; struct Base { Base() { //Is there a way to make it work? //Derived* d = static_cast<Derived*>(this); } }; struct Derived: public Base { }; int main() { Base b{}; // Here it works as the compiler is aware of the relationship Derived* d = static_cast<Derived*>(&b); }
更新说明
我知晓示例代码存在问题,仅用于演示场景,实际业务逻辑更为复杂。我有一个编译时切换的不透明指针(opaque pointer),指向Base或Derived类型:
#ifdef PLATFORM_A typedef struct Derived UsedType; #else typedef struct Base UsedType; #endif
需要在Base构造函数中获取该不透明指针,此时this指针实际指向Base或Derived实例。当定义PLATFORM_A时,Base仅能通过Derived实例化,转换是安全的;未定义PLATFORM_A时,UsedType即为Base,无需转换。但由于Base构造函数中仅存在Derived的前向声明,编译器无法识别继承关系,导致static_cast无法使用。
更新3:带const成员的场景代码
#include <iostream> #define PLATFORM_A #ifdef PLATFORM_A typedef struct Derived UsedType; #else typedef struct Base UsedType; #endif struct User { UsedType* const platform; void print() const; }; struct Base { const char* const name{"Base"}; User const iNeedThis; #ifdef PLATFORM_A protected: #endif Base() : iNeedThis{(UsedType*)this} //: iNeedThis{static_cast<UsedType*>(this)} { } }; #ifdef PLATFORM_A struct Derived: public Base { const char* const name{"Derived"}; Derived() : Base() { } }; #endif void User::print() const { std::cout << platform->name << std::endl; } int main() { UsedType myObj{}; myObj.iNeedThis.print(); }
针对你的场景,这里提供两种无需reinterpret_cast的合法实现方案:
方案1:模板构造函数传递类型上下文
核心思路是将转换逻辑转移到Derived构造函数的上下文(此时编译器已完整知晓继承关系),通过模板构造函数将类型信息传递给Base:
#include <iostream> #define PLATFORM_A #ifdef PLATFORM_A typedef struct Derived UsedType; #else typedef struct Base UsedType; #endif struct User { UsedType* const platform; void print() const; }; struct Base { const char* const name{"Base"}; User const iNeedThis; private: // 私有构造函数,负责最终的指针转换与初始化 explicit Base(void* ptr) : iNeedThis{static_cast<UsedType*>(ptr)} {} public: #ifdef PLATFORM_A protected: #endif // 非PLATFORM_A场景的默认构造 Base() : Base(static_cast<void*>(this)) {} // 模板构造函数,供Derived调用时传递自身类型 template<typename DerivedType> explicit Base(DerivedType*) : Base(static_cast<void*>(this)) {} }; #ifdef PLATFORM_A struct Derived: public Base { const char* const name{"Derived"}; Derived() : Base(static_cast<Derived*>(this)) {} }; #endif void User::print() const { std::cout << platform->name << std::endl; } int main() { UsedType myObj{}; myObj.iNeedThis.print(); }
Derived构造时调用Base的模板构造函数,此时编译器已经知道Derived继承自Base,static_cast<Derived*>(this)是合法的,随后通过私有构造函数完成UsedType*的转换与iNeedThis的初始化。
方案2:编译时断言+void指针中转
利用预编译指令区分场景,通过static_cast<void*>绕过前向声明的继承关系限制,同时用编译时断言保证转换安全性:
#include <iostream> #include <type_traits> #define PLATFORM_A #ifdef PLATFORM_A struct Derived; typedef Derived UsedType; #else typedef struct Base UsedType; #endif struct User { UsedType* const platform; void print() const; }; struct Base { const char* const name{"Base"}; User const iNeedThis; #ifdef PLATFORM_A protected: #endif Base() #ifdef PLATFORM_A : iNeedThis{static_cast<UsedType*>(static_cast<void*>(this))} #endif #ifndef PLATFORM_A : iNeedThis{static_cast<UsedType*>(this)} #endif { #ifdef PLATFORM_A // 编译时断言,确保Derived必须继承自Base static_assert(std::is_base_of_v<Base, Derived>, "Derived must inherit from Base"); #endif } }; #ifdef PLATFORM_A struct Derived: public Base { const char* const name{"Derived"}; Derived() : Base() {} }; #endif void User::print() const { std::cout << platform->name << std::endl; } int main() { UsedType myObj{}; myObj.iNeedThis.print(); }
在PLATFORM_A场景下,先将this转换为void*(无需继承关系信息),再转换为UsedType*,同时通过static_assert在编译期强制检查Derived与Base的继承关系,避免非法转换。
内容的提问来源于stack exchange,提问作者Broothy

