   [C++] Member Function Pointer Madness (?)
  Hello,I've inherited a super-messy C++ project from a coworker who's left the company ... let's just call him Jim (not his real name). At present I'm trying to replace any C-style casts with proper C++ casts. I've come across a piece of code that does something which I find rather weird. I'm suspecting that this may not even be valid C++, but I'm not sure so I thought I'd ask the forum.So here goes ... say you have a base class, called Base. Base has a number of methods, their precise nature is not important for this example.class Base{public:void foo();void bar();};Then you go and define a type of pointer that points to one of those member functions, like so:typedef void ( Base::*FuncPtr )();Now we add another class, called Derived, which - you guessed it - is derived from Base. Derived does not reimplement any of the functions it inherits from Base (none of the functions in Base are virtual anyway), but it does define an additional method:class Derived : public Base{public:void someMethod();};There is nothing weird going on in the code I've posted yet. So far, everything is just fine (IMO). Next comes the suspicious part (using C-style casts as I found them in Jim's code).Derived d;Base* objectPtr = &d; // <--- OKFuncPtr ptrToFunc = ( FuncPtr ) ( &Derived::someMethod ); // <--- Does C++ allow this???The cast above is not possible using static_cast. The fact that a reinterpret_cast is required to make this work rings some alarm bells in my head. The code does seem to work as intended, but it still leaves me with an uneasy feeling that the effects of doing something like this might at best be 'undefined'. Is my suspicion correct?   
  My gut feeling tells me that this can't be right. A pointer-to-member-function is like an offset into a vtable. But in Base, there is no entry for that offset. If it were legal, you surely wouldn't require a cast in the first place.But this is just guessing.   ;  As we are converting pointers to functions with the same signature, the code looks fine for me. And even with -Wall -Wextra -pedantic, I get not even a warning with a static_cast<>, in g++ 3.x.Adding a conversion to a pointer-to-function of a different signature, I succeed to fail:typedef void ( Base::*FuncPtr2 )(int);FuncPtr2 ptrToFunc2 =  static_cast<FuncPtr2>( &Derived::someMethod );typedef int ( Base::*FuncPtr3 )();FuncPtr3 ptrToFunc3 =  static_cast<FuncPtr3>( &Derived::someMethod );Each gives me an invalid conversion.I guess this works because those are both non-virtual, non-static, functions, and the calling convention for those is the same.edit: forgot to mention that I actually defined Derived::someMethod().   ;  Hmmm, I just found an identical example in Stroustrup's The C++ Programming Language, section 15.5.1 Base and Derived Classes, where he states that Quote:[...] by refusing the initialization, the compiler saves us from a run-time error.;  Consider refactoring to use interfaces rather than member function pointers.  There's always boost::bind and the like or a non-member wrapper function if that's not an option.Also, casting function pointers is rather evil.   ;Quote:Original post by Red AntThe cast above is not possible using static_cast. The fact that a reinterpret_cast is required to make this work rings some alarm bells in my head. The code does seem to work as intended, but it still leaves me with an uneasy feeling that the effects of doing something like this might at best be 'undefined'. Is my suspicion correct?No, this should be allowed by a static_cast. A static_cast can be used to reverse any implicit conversion, and contravariance means that there's a conversion from void (Base::*)(void) to void (Derived::*)(void), so a static_cast can be used to perform the reverse.   ;  Hmm, I just tried the same on Visual C++ 2005, and here it works ... although it does require a static_cast ... if you don't use a cast at all the compiler barfs.The SUN forte compiler doesn't even accept a static_cast and insists on a reinterpret_cast. Also, why does Stroustrup claim that the conversion is not allowed?   ;  The standard has this note:Quote:If class B contains the original  member,  or is a base or derived class of the class containing the original member, the resulting pointer to member  points  to  the  original member. Otherwise,  the  result  of  the  cast is undefined.[Note:  although class B need not contain the  original  member,  the  dynamic   type of the object on which the pointer to member is dereferenced must contain the original member.  ]So you can call someMethod through that cast pointer if you actually have an instance of Derived, but shouldn't do it if you have an instance of Base (can't call validly methods that a class doesn't have).   ;  Looks legal, but it's obviously playing with fire.If objectPtr and ptrToFunc are heavily related enough (as they hopefully are with code like this, with the assumptions it makes!), it might be feasible to replace the both of them with a boost::function, which would have the added advantage of making this type safe:boost::function< void () > f = boost::bind( &Derived::someMethod, &d );(objectPtr->*ptrToFunc)();f();;  Thanks, guys, that has cleared it up for me.As to the suggestion to use boost::function, I wish I could. Alas, our project doesn't use boost (not my decision, I'm obviously not the project manager). But we do use the ACE library (albeit a stone age version of it), so maybe I should go looking for something similar to boost::function in ACE.P.S. It scares me that even after 8 years of C++, I'm still occasionally surprised by some aspects of the language. :\   