C++03 标准,§4.11 2 指向成员转换的指针:
“指向类型为cv T 的 B 的成员的指针”类型的右值,其中 B 是类类型,可以转换为类型为“指向类型为cv T 的 D 的成员的指针”类型的右值,其中 D 是派生类 ( B 的第 10 条)。如果 B 是 D 的不可访问(第 11 条)、模棱两可(10.2)或虚拟(10.1)基类,则需要进行这种转换的程序是格式错误的。转换的结果与发生转换之前的成员指针引用相同的成员,但它引用基类成员,就好像它是派生类的成员一样。结果引用了 D 的 B 实例中的成员。由于结果的类型为“指向cv类型的 D 成员的指针”T,”它可以用 D 对象取消引用。结果与使用 D 的 B 子对象取消引用 B 的成员的指针相同。空成员指针值转换为目标类型的空成员指针值。52)
52)与指向对象的指针规则(从派生指针到基址指针)相比,成员指针转换规则(从基址成员指针到派生成员指针)似乎相反(4.10,第 10 条) . 这种反转是确保类型安全所必需的。请注意,指向成员的指针不是指向对象的指针或指向函数的指针,并且此类指针的转换规则不适用于指向成员的指针。特别是,指向成员的指针不能转换为 void*。
简而言之,您可以将指向可访问的、非虚拟基类的成员的指针转换为指向派生类成员的指针,只要该成员不模棱两可。
class A {
public:
void foo();
};
class B : public A {};
class C {
public:
void bar();
};
class D {
public:
void baz();
};
class E : public A, public B, private C, public virtual D {
public:
typedef void (E::*member)();
};
class F:public E {
public:
void bam();
};
...
int main() {
E::member mbr;
mbr = &A::foo; // invalid: ambiguous; E's A or B's A?
mbr = &C::bar; // invalid: C is private
mbr = &D::baz; // invalid: D is virtual
mbr = &F::bam; // invalid: conversion isn't defined by the standard
...
另一个方向(通过static_cast
)的转换受§ 5.2.9 9 的约束:
“指向cv1 T 类型的 D 成员的指针”类型的右值可以转换为“指向cv2 T 类型的 B 成员的指针”类型的右值,其中 B 是 D 的基类(第10 条 class.derived) ,如果存在从“指向 T 类型 B 成员的指针”到“指向 T 类型 D 成员的指针”的有效标准转换(4.11 conv.mem),并且cv2与 cv-qualification 相同或更高资格比,cv1。11)空成员指针值(4.11 conv.mem) 转换为目标类型的空成员指针值。如果类 B 包含原始成员,或者是包含原始成员的类的基类或派生类,则指向成员的结果指针指向原始成员。否则,强制转换的结果是未定义的。[注意:虽然B类不需要包含原始成员,但解除引用成员指针的对象的动态类型必须包含原始成员;见5.5 expr.mptr.oper。]
11)函数类型(包括那些用于指向成员函数类型的指针)永远不是 cv 限定的;见8.3.5 dcl.fct。
简而言之,如果可以从 a 转换为 a ,则可以从派生转换为基D::*
,尽管您只能使用D 类型或从 D 派生的 on 对象。B::*
B::*
D::*
B::*