user1132655
user1132655

Reputation: 243

c++ passing self to self mistery

could you please help me. I am passing self to a pure virtual function of itself.

n->dataCallback(handler, n, hangup);

where n is my class pointer and dataCallback is its own (pure) virtual function (I know it makes no sense, I just wonder why it happens what I describe below).

so now in the declaration:

void MyClass::dataCallback(int handler, void *cbData, bool hangup) {
    MyClass *This = (MyClass*) cbData;
 ....
}

Now when I compare This (the varaiable above) to this (the pointer of the object) at runtime I get:

  1. The values of the poiners (the addresses of the object) are different.
  2. When checking a memeber varaible (This->member) I find different values in them. (The correct value is in this, whereas This contains an undefined (to me random) value. Note, that on the caller side the value is of course correct so it seems to magically change during the call itself, and there is no other code in between.

How on earth is this possible? Any Idea?

I've spent 2 hours meditating on this, also asked other programmers with no results.

Upvotes: 0

Views: 274

Answers (3)

Mike Seymour
Mike Seymour

Reputation: 254631

This can happen if n is a pointer to a class derived from the one that implements dataCallback, and this class has multiple base classes. Only one (non-empty) base object can have the same address as the complete object. Here is an example that illustrates the problem:

#include <iostream>

struct Base {
    int stuff;
    virtual void f(void * p) {
        std::cout << (p == this ? "GOOD\n" : "BAD\n");
    }
};

struct Other {
    int stuff; 
    virtual void g() {}
};

struct Derived : Other, Base {};

int main()
{
    Derived t;
    t.f(&t);     // BAD: Passing pointer to Derived to member of Base
                 // (but not guaranteed to print "BAD" - layout is not specified)

    Base & b = t;
    b.f(&b);     // GOOD: Passing pointer to Base to member of Base
}

Upvotes: 0

Mark Ransom
Mark Ransom

Reputation: 308432

If you have multiple inheritance, casting a pointer to each of the parent classes may change the pointer address. Consider the following:

class A
{
public:
    int a;
};

class B
{
public:
    int b;
};

class C : public A, B
{
};

The internal layout of class C will contain two integers a and b. If you cast a pointer from C* to A* all is well. If you cast it to B*, the pointer will need to be adjusted because the first element in a B must be the integer b!

If you do a cast where both types are known to the compiler, it will do the adjusting in a way which is invisible to you - it just works. The compiler knows what the proper adjustment should be. When you cast to void* this mechanism gets broken.

Upvotes: 2

Lightness Races in Orbit
Lightness Races in Orbit

Reputation: 385284

We don't have a full testcase to work with, but if MyClass is polymorphic and related classes exist, then casting can alter the pointer value. The use of void* may be breaking that.

Upvotes: 0

Related Questions