Re: Casting of pointer to member functions
 
"David Olsson" wrote:
I am writing an application in which I use pointer to 
member functions
to achieve a certain functionality. At one point I need to 
be able to
cast between different types of member function. In a very 
simplified
version, this is what I want to do:
class Base {
public:
  typedef void (Base::*MethodPrototype)();
  Base(MethodPrototype method): m_method(method) {}
  void call() {
     (this->*m_method)();
  }
private:
  MethodPrototype m_method;
};
class Derived: virtual public Base {
public:
  Derived():
Base(reinterpret_cast<MethodPrototype>(&Derived::myMethod)) 
{}
  int myMethod() {
     return(1);
  }
};
The constructor of the Derived class failes to compile as 
visual c++
reports that the reinterpret_cast is invalid. This does 
however only
occur when the inheritance is virtual, if it isn't 
virtual, the casting
works fine. Furthermore, the above code compiles with GCC 
3.4.2. Is it
Visual C++ or GCC that isn't quite conformant. And is 
there a
workaround to be able to do this?
Even if it will compile I wonder whether it will work 
properly. Pointers to members can differ in their sizes from 
4 to 16 bytes. The error you get tells you that pointer to 
Derived member cannot fit into pointer to Base member. When 
you remove `virtual' modifier pointers have the same size, 
so compiler can assign `&Derived::myMethod' to variable of 
`MethodPrototype' type.
You can safely cast pointer to member to other type (which 
must be poiner to member, too) only in case you intend to 
cast it back before any usage. That's the only thing that 
Standard guarantees you:
<quote>
5.2.10/9 Reinterpret cast
An rvalue of type "pointer to member of X of type T1" can be 
explicitly converted to an rvalue of type "pointer to member 
of Y of type T2" if T1 and T2 are both function types or 
both object types. The null member pointer value (4.11) is 
converted to the null member pointer value of the 
destination type. The result of this conversion is 
unspecified, except in the following cases:
? converting an rvalue of type "pointer to member function" 
to a different pointer to member function type and back to 
its original type yields the original pointer to member 
value.
? converting an rvalue of type "pointer to data member of X 
of type T1" to the type "pointer to data member of Y of type 
T2" (where the alignment requirements of T2 are no stricter 
than those of T1) and back to its original type yields the 
original pointer to member value.
</quote>
In your specific case you can use /vmg compiler switch, so 
compiler will assume the worst case all the time and 
generate pointers to member large enough to accommodate to 
any input. However, when class hierarchy will expand and/or 
`Derived::myMethod' will access data members, then you're 
likely to crash inside `Base::call' because necessary `this' 
adjustments won't be performed.
HTH
Alex