------- Comment #4 from bangerth at dealii dot org 2006-09-27 04:50 ------- This code can't work. The check() function is not a virtual function, so calling ((&broken)->*func) (); is translated to ( ((Base*)(&broken))->*func) (); because func is of type void (Base::*) (...) Then, when you call func, you really mean a function in the derived class, so a this-pointer adjustment would be necessary, but due to the invalid cast of &Broken::check this isn't happening. So *this has the wrong value.
The fact that it works in the Works class is simply because Base is the first base class there, and therefore the this-pointer adjustment does nothing, so you get lucky. As for the validity of the testcase, here's a redux: ------------------- struct B {}; struct D { void f();}; typedef void (B::*BaseFunPtr)(); BaseFunPtr p = (BaseFunPtr)&D::f; ------------------- Without the C-style cast in the last line, the code is rightfully rejected. 5.4/6 explicitly allows the cast as legal. However, 5.5/3 says that 3 The binary operator ->* binds its second operand, which shall be of type "pointer to member of T" (where T is a completely-defined class type) to its first operand, which shall be of type "pointer to T" or "pointer to a class of which T is an unambiguous and accessible base class." The result is an object or a function of the type specified by the second operand. The problem is that the rhs is "pointer to member of Broken", whereas the left hand side is "pointer to Base", for which Broken is not an unambiguous and accessible base class (in fact, the opposite statement is true). The code is therefore invalid and has undefined behavior as per the use of objects using the wrong type (here a pointer to member of derived that isn't cast back to its real type). W. -- bangerth at dealii dot org changed: What |Removed |Added ---------------------------------------------------------------------------- CC| |bangerth at dealii dot org Status|UNCONFIRMED |RESOLVED Resolution| |INVALID http://gcc.gnu.org/bugzilla/show_bug.cgi?id=29243