Search code examples
c++pointer-to-memberthis-pointer

Address of pointer "this" changed unexpectedly inside a pointer to member function call


I have problem with the pointer to member function call. The address of pointer "this" outside the function pointer call is different than inside the call thus all access to the class variables results wrong values.

I include the code here.

class ClassInterface
{
public:
    ClassInterface(void);
    ~ClassInterface(void);
};

class ClassA:public ClassInterface
{
public:
    float   _a;
public:
    ClassA(void);
    ~ClassA(void);

    virtual void Update();
};


class ClassB:public ClassA
{
public:
    ClassB(void);
    ~ClassB(void);

    void Update();

    void ProcessTaskB(void*);
};

//ClassB.CPP
void ClassB::ProcessTaskB(void*)
{
    printf("ClassB::ProcessTaskB\n");

    printf("Address of myB INSIDE callback = %d\n",this);
    _a += 100;
}

//test CPP
#include "stdafx.h"
#include "ClassInterface.h"
#include "ClassA.h"
#include "ClassB.h"

typedef void (ClassInterface::*Callback) (void* );

int _tmain(int argc, _TCHAR* argv[])
{
    ClassA* myA = new ClassA();
    ClassB* myB = new ClassB();

    Callback fptrB = (Callback) &(ClassB::ProcessTaskB);

    printf("Address of myB outside callback = %d\n",myB);

    (myB->*fptrB)(NULL);

    return 0;


}

And this is the output:

Address of myB OUTSIDE callback = 1332696
Address of myB INSIDE callback = 1332700

Thus the statement _a += 100; does not make change to _a. It made change to address (&_a + 4).

I have no clue to resolve this. Please help me fix.


Solution

  • In your updated form your code is perfectly correct and has no problems whatsoever. The only explanation for the incorrect behavior is that you must be using MSVC++ compiler in some "restricted" member pointer model (which works incorrectly in general case). In fact, I believe MSVC++ compiler issues the corresponding warnings when you attempt to convert your member pointers. Did you just ignore the warning?

    Anyway, add

    #pragma pointers_to_members( full_generality, virtual_inheritance )
    

    to you code in order to enable full functionality of member function pointers required by C++ standard, and your code should work fine. In your case this

    #pragma pointers_to_members( full_generality, multiple_inheritance )
    

    should be sufficient though. Compiler options from /vmm, /vms, /vmv group in combination with /vmg achieve the same effect.

    Also, avoid C-style casts in such contexts. The conversion you are using is performed by static_cast

    Callback fptrB = static_cast<Callback>(&ClassB::ProcessTaskB);
    

    Also, don't attempt to print pointers with %d format specifier in printf. This is another undefined behavior right there. Printing pointers is what %p format specifier is for.