Search code examples
c++classcastingreinterpret-cast

How does casting this pointer to an unrelated class work?


This confuses me because if "this" points to its own object, how would casting it (without inheritance) allow me to access other class members? I think I'm just overall confused on what exactly casting "this" is doing for the compiler, considering its address doesn't change.

template<class T>
class A 
{
public:
    void call_fn()
    {
        reinterpret_cast<T*>(this)->fn();
    }
};

class B
{
public:
    void fn()
    {
        std::cout << "B function called" << std::endl;
    }
};

int main()
{
    A<B> obj;
    obj.call_fn(); //prints out "B function called"
}

Solution

  • A non-static method call is just like a plain function call but with a hidden this parameter pointing at the object. The code shown is roughly equivalent to the following:

    class A {};
    class B {};
    
    void B_fn(B* this);
    
    void A_call_fn(A* this) {
        B_fn(reinterpret_cast<B*>(this));
    }; 
    
    void B_fn(B* this) {
        std::cout << "B function called" << std::endl;
    }
    
    int main() {
        A obj;
        A_call_fn(&obj);
    }
    

    A::call_fn() is type-casting its A* this parameter to B*, and then calling B::fn() with that casted pointer as its B* this parameter value. A reinterpret_cast is effectively a brute-force cast, it really goes out of its way to try to oblige your request. So you are telling the compiler that you know what you are doing and just accept it. So it does. But you are invoking undefined behavior, because like you said, A and B are unrelated types.

    The code happens to work, but only because B::fn() makes no use of its B* this parameter, so it doesn't matter whether this is actually pointing at a valid B object or not. The code is ultimately no different than if you had done this instead:

    int main() {
        std::cout << "B function called" << std::endl;
    } 
    

    But, if you were to change B to hold a non-static data member that B::fn() actually uses, then the code will fail more noticeably.