1

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.

mleko
  • 11,650
  • 6
  • 50
  • 71
user2512031
  • 15
  • 1
  • 4

1 Answers1

1

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.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765
  • I wouldn't necessarily equate *different* and *broken* `this` pointer. There could be multiple inheritance at play in the parts of the code we haven't been shown. – NPE Aug 09 '14 at 17:37
  • Say, doesn't the problem indicate that `ClassInterface` doesn't have a V-Table and `ClassB` does? (although it's not apparent in the code provided by OP). – barak manos Aug 09 '14 at 17:42
  • @barak manos: The problem is *triggered* by the introduction of a vtable pointer in `ClassA`. However, C++ standard requires this code to work correctly. In order to make it work correctly the OP has to switch his compiler from "simplified" member pointer support mode to "full standard" member pointer support mode. And everything will start working as expected. – AnT stands with Russia Aug 09 '14 at 17:53
  • @AndeyT: I tried your solution but it doesn't work out. the address still different. – user2512031 Aug 09 '14 at 17:53
  • @user2512031: The solution is correct and it works perfectly. You must have placed the `#pragma` in a wrong place. It has to be at the very top and has to be visible in every file. Anyway, forget about pragma and better change the global project settings instead. – AnT stands with Russia Aug 09 '14 at 17:54
  • `Address of myB outside callback = 00662EE8` `ClassB::ProcessTaskB` `Address of myB INSIDE callback = 00662EE8` – AnT stands with Russia Aug 09 '14 at 17:57
  • Shouldn't `single_inheritence` be enough? I don't see any MI. – Deduplicator Aug 09 '14 at 17:58
  • @Deduplicator: I don't see it either. However, I don't know exactly why, but the compiler explicitly says in the warning message that in this case `multiple_inheritance` or higher is required. I think that when you introduce a vtable pointer in the middle of the hierarchy, the complexity of situation becomes "just like multiple inheritance". So the compiler wants `multiple_inheritance` at least. – AnT stands with Russia Aug 09 '14 at 18:00
  • @AndreyT I added /vmm, /vms, /vmv to CommandLine/Additional options but the output when rebuilding the program say:cl : Command line warning D9002: ignoring unknown option '/vmm,' 1>cl : Command line warning D9002: ignoring unknown option '/vms,' – user2512031 Aug 09 '14 at 18:07
  • What compiler are you using? What version? Anyway, in my VS 2013 the compiler does not complain about the options, but still `/vmm` has no effect. Pragma works, but `/vmm` does not. I don't know what's wrong yet.... – AnT stands with Russia Aug 09 '14 at 18:12
  • I got it. It needs two options: `/vmg /vmm`. Then it works in my case. – AnT stands with Russia Aug 09 '14 at 18:15
  • @AndreyT: I just put "#pragma pointers_to_members( full_generality, virtual_inheritance )" as you said before on top of ClassInterface.h instead and it worked out. Many thanks! I'm using VC++ 2010 express – user2512031 Aug 09 '14 at 18:16
  • @AndreyT: will this solution work on Xcode? Since I working on cross platform project. – user2512031 Aug 09 '14 at 18:18
  • I'd expect `/vmg /vmm` to work in VS2010... Are you sure you put these options to the compiler command line (as opposed to linker command line)? – AnT stands with Russia Aug 09 '14 at 18:18
  • @user2512031: This is a MSVC-specific problem. Most other standard C++ compilers will handle this code properly without you having to do anything at all. Your code is correct as is. – AnT stands with Russia Aug 09 '14 at 18:19