根据 C++11 规范草案 n4296,5.2.10 重新解释强制转换 [expr.reinterpret.cast] §10
如果 T1 和 T2 都是函数类型或都是对象类型,则“指向 T1 类型 X 成员的指针”类型的纯右值可以显式转换为不同类型“指向 T2 类型 Y 成员的指针”的纯右值。 72
null 成员指针值 (4.11) 转换为目标类型的 null 成员指针值。此转换的结果未指定,但以下情况除外:
— 将“指向成员函数的指针”类型的纯右值转换为不同的指向成员函数的指针
类型并返回其原始类型会产生指向成员值的原始指针。
— 将“指向 T1 类型 X 的数据成员的指针”类型的纯右值转换为“指向数据的指针”类型
T2 类型 Y 的成员”(其中 T2 的对齐要求不比 T1 严格)
并返回其原始类型,产生指向成员值的原始指针。
转换为指向不带参数的成员函数的指针并返回到具有正确参数的成员函数应该返回原始指针。
恕我直言,问题是fooCallback
仅定义于DerivedView
类,因此它是not类的成员函数AView
.
这是正确的:
void (AView::*p)() = reinterpret_cast<void (AView::*)()>(&DerivedView::fooCallback);
void (DerivedView::*callback)(std::string, int, double) =
reinterpret_cast<void (DerivedView::*)(std::string, int, double)>(p);
v->callback("Hello World"), 42, 84.42);
假如v
is a AView *
指向一个DerivedView
但是当你结束转换时void (DerivedView::*)(std::string, int, double)
to a void (AView::*)(std::string, int, double)
它们是不同的类型,因此未指定转换
它有效,因为非静态非虚拟成员函数的常见实现只是一个普通(非成员)函数,其隐藏参数为this
。因此,指向成员的指针仅存储该函数的地址,并使用指向 a 的指针正确调用它DerivedView
给出预期的结果。但不同的实现也可以存储实际类型并引发异常(或执行其他操作)。
TL/DR:当你以从void (DerivedView::*)(std::string, int, double)
to void (AView::*)(std::string, int, double)
您不会将指向成员的指针转换为其原始类型并调用未定义的行为。