Search code examples
c++reinterpret-cast

I accidentally called a member function without own class object. But how does this work?


Here is my code.

class IService {
};

class X_Service {
public:
    void service1() {
        std::cout<< "Service1 Running..."<<std::endl;
    }
};


int main() {
    IService service;
    auto func = reinterpret_cast<void (IService::*)()>(&X_Service::service1);
    (service.*(func))();
    return 0;
}

I don't understand how this works. I didn't inherit IService and didn't create a X_Service object but it works. Can someone explain this?


Solution

  • So, I had some fun and manipulated the code a bit. This is also an empirical answer. There are a lot of pitfalls that risk stack corruption with this way of doing things, so I changed the code a bit to make it to where stack corruption does not occur but kind of show what it happening.

    #include <iostream>
    
    class IService {
    public:
        int x;
    };
    
    class X_Service {
    
    public:
        int x;
        void service1() {
            this->x = 65;
            std::cout << this->x << std::endl;
        }
    };
    
    
    int main() {
        IService service;
        auto func = reinterpret_cast<void (IService::*)()>(&X_Service::service1);
        (service.*(func))();
        std::cout << service.x << std::endl;
        std::cin.get();
        X_Service derp;
        (derp.service1)();
        std::cout << derp.x << std::endl;
    
    
        return 0;
    }
    

    So from the outset, auto gave you the power to make a none type safe pointer void (IService::*)()also the instance of the object itself is this-> regardless of what member function of whatever class you are stealth inheriting from. The only issue is that the first variable of the instance is interpreted based on the first variable of the class you are stealth inheriting from, which can lead to stack corruption if the type differs.

    Ways to get cool output but inevitably cause stack corruption, you can do the following fun things.

    class IService {
    public:
        char x;
    };
    

    Your IDE will detect stack corruption of your IService object, but getting that output of

    65
    A
    

    is kind of worth it, but you will see that issues will arise doing this stealth inheritance.

    I'm also on an 86x compiler. So basically my variable are all lined up. Say for instance if I add an int y above int x in Iservice, this program would output nonsense. Basically it only works because my classes are binary compatible.