通过基类成员函数指针调用派生类非虚成员函数是否合法?
派生类成员函数指针转基类后通过基类指针调用的合法性问题
派生类的成员函数指针可以通过static_cast转换为基类B的成员函数指针。C++20草案的[expr.static.cast]中有一条注释:
[注:尽管类B无需包含原成员,但通过成员指针间接操作的对象的动态类型必须包含该原成员;参见7.6.4。——结束注]
7.6.4的相关内容如下:
将pm-expression.*cast-expression缩写为E1.*E2,E1称为对象表达式。若E1的动态类型不包含E2所指向的成员,则行为未定义。否则,表达式E1先于表达式E2执行。
从这两点来看,似乎都只强调对象的动态类型是关键,所以我原本认为:通过派生类对象的基类子对象指针调用这类转换后的非虚成员函数指针是合法的。我用GCC、Clang和MinGW测试了代码(见下文),确实能正常运行,但在MSVC中却触发了断言。
如果这种调用是非法的,那标准里特意强调E1的“动态类型”意义何在?
另外,cppreference上的表述略有不同,涉及成员函数指针反向转换的文本及后续示例,但该示例是在派生类对象上调用基类成员指针,并未解释E1“动态类型”的意义。不过我发现,当E1的静态类型为派生类本身时,MSVC中的断言不会触发。
测试代码如下:
#include<cassert> #include<type_traits> struct B{ }; struct A1{ int arr[8]; }; struct A2{ long double arr[8]; }; struct D1 : A1, B { int md1 = 13; int f1() const { return md1; } }; struct D2 : A2, B { int md2 = 2; int f2() const { return md2; } }; int main() { D1 d1; D2 d2; B *pb1 = &d1, *pb2 = &d2; auto pmf1 = static_cast<int (B::*)() const>(&D1::f1); auto pmf2 = static_cast<int (B::*)() const>(&D2::f2); assert( (pb1->*pmf1)()==13 ); //MSVC中触发断言 assert( (pb2->*pmf2)()==2 ); //MSVC中触发断言 }
内容的提问来源于stack exchange,提问作者Adrian
相关产品推荐
相关产品推荐

