无需强制转换,能否用指向基类成员的指针指向派生类成员?
指向成员指针与派生类成员的类型转换问题
这个问题其实戳中了C++里指向成员指针(pointer-to-member)的一个容易被误解的规则:普通指针的派生类到基类隐式转换规则,并不适用于指向成员的指针。
为什么代码会报错?
你写的代码里:
Base1 Base2::*ptr2 = &Base2::d; // 报错
编译器提示无法从Derived Base2::*转换为Base1 Base2::*,本质原因是:
- 指向成员的指针
T C::*的核心是“标记包含类C中一个类型为T的成员”,它的类型绑定了包含类和成员类型两个维度。 - 虽然
Derived继承自Base1,但Base2中的d是Derived类型成员,和Base1类型成员是完全不同的“成员类型”,C++类型系统不允许这种跨类型的隐式转换——这和普通指针Derived*可以转成Base1*的逻辑不一样,因为普通指针指向的是对象,而成员指针指向的是“包含类中的成员位置+类型”。
无需强制转换的可行方案?
很遗憾,在标准C++中,没有办法不通过强制转换就把Derived Base2::*隐式转成Base1 Base2::*,因为这两种成员指针在类型系统中被判定为“无关类型”。不过我们可以换一种思路来实现你的需求,同时避免强制转换:
方案1:保持成员指针类型,访问时转换成员
如果你只是需要访问Derived成员中的Base1部分,可以保留Derived Base2::*类型的指针,在实际访问成员时,利用派生类到基类的隐式转换获取Base1引用:
void foo() { Derived Base2::*ptr = &Base2::d; Base2 obj; // 利用Derived到Base1的隐式转换,得到Base1的引用 Base1& base_part = obj.*ptr; // 现在可以安全访问Base1的成员 base_part.m = 42; }
这种方式完全符合类型安全规则,不需要任何强制转换,也能满足你访问派生类中基类成员的需求。
方案2:使用强制转换(仅当必须时)
如果你的场景必须得到Base1 Base2::*类型的指针,那只能使用强制转换。在非虚继承且Base1是Derived的第一个基类的情况下,reinterpret_cast是可行的(因为此时Derived对象中Base1子对象的偏移为0):
Base1 Base2::*ptr2 = reinterpret_cast<Base1 Base2::*>(&Base2::d);
不过要注意,这种转换依赖具体的内存布局,不是完全可移植的,属于“依赖实现细节”的写法,需要谨慎使用。
总结
- 优先推荐方案1:保持派生类成员指针类型,访问时转换为基类引用,既安全又符合标准。
- 只有在必须得到基类成员指针类型的场景下,才考虑方案2的强制转换,且要注意内存布局的兼容性。
内容的提问来源于stack exchange,提问作者SoronelHaetir
相关产品推荐
相关产品推荐

