Posted on July 29, 2008 in C++, Programming by adminComments

Member function pointers

In the C# era we are living, it’s more and more important to have efficient notifications callbacks in C++. We have standard C callbacks notifications, and member function pointers.

They are usually declared as typedef void (CMyClass::*MyTypeDefName)(Parameters);and called with (pMyClass->*)m_MyCallback(params);

I used in a project it to have a simple template signal class. Today, we came across a bug : an object’s constructor was not initializing properly, filling wrong members with wrong values. It seemed he did’nt knew the right offsets for its own class ! Interesting thing, this object contained member function pointers…

Visual C++ weird implementation

The answer was “In Visual C++, member function pointers have different sizes, depending on what compiler knows about the target class”. As explained in this thread (2nd post) the member function pointers can vary from 4 bytes to 16 bytes.

16 bytes is for classes that are forward declared even if you fully declare them after ! See example below:

Case 1

class CForward {}; // full declaration only
typedef void (CForward::*FnType)(int); // sizeof(FnType) == 4

Case 2

class CForward; // forward declaration
typedef void (CForward::*FnType)(int);  // sizeof(FnType) == 16

Case 3

class CForward; // forward declaration
class CForward {}; // full declaration
typedef void (CForward::*FnType)(int);  // sizeof(FnType) == 16

So, if you forward declare a class, and include this class header, any function pointer to this class will be 16 bytes. If you only include the header, pointer will vary from 4 to 12 bytes (depending on the class).

As said in the thread, the simplest solution is to use VC++ #pragma directive, included everywhere in your code (MSDN link here)

// will force all pointers to 16 bytes
#pragma pointers_to_members(full_generality, virtual_inheritance) 

// will force all pointers to 8 bytes, use if you don't have
// virtual inheritance (general case)
#pragma pointers_to_members(full_generality, multiple_inheritance)

// will force all pointers to 4 bytes, use if you don't have
// multiple inheritance
#pragma pointers_to_members(full_generality, single_inheritance)

In strongly encourage you to use one of these methods (or to use /vmg compiler switch), to be sure all the function pointers of your code have the same size !

Don’t be afraid of using a restrictive pragma directive, VC++ throws an error message if you use too restrictive pointers: error C2287: inheritance representation: ’single_inheritance’ is less general than the required ‘multiple_inheritance’

References