我不小心调用了一个没有自己的类对象的成员函数。但这是如何工作的?

s3m*_*3ms 5 c++ reinterpret-cast

这是我的代码。

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;
}
Run Code Online (Sandbox Code Playgroud)

我不明白这是如何工作的。我没有继承 IService 也没有创​​建 X_Service 对象,但它可以工作。有人可以解释一下吗?

sup*_*per 8

您的困惑可能来自误解,因为某些东西可以编译并运行而不会崩溃,因此它“有效”。这不是真的。

有很多方法可以打破语言规则,仍然编写可编译和运行的代码。通过reinterpret_cast在此处使用并进行无效转换,您违反了语言规则,并且您的程序具有未定义的行为。

这意味着它看起来可以工作,也可以崩溃,或者它可以做一些与你想要的完全不同的事情。

在您的情况下,它似乎有效,但它仍然是 UB 并且代码无效。


Mar*_*cus 2

所以,我玩得很开心,并对代码进行了一些操作。这也是一个经验性的答案。这种做法存在很多陷阱,可能会导致堆栈损坏,因此我对代码进行了一些更改,以使其不会发生堆栈损坏,但会显示发生的情况。

#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;
}
Run Code Online (Sandbox Code Playgroud)

因此,从一开始,auto您就可以创建一个非类型安全指针,void (IService::*)()并且对象本身的实例也是this->如此,无论您隐式继承的任何类的成员函数是什么。唯一的问题是,实例的第一个变量是根据您隐式继承的类的第一个变量来解释的,如果类型不同,这可能会导致堆栈损坏。

获得很酷的输出但不可避免地导致堆栈损坏的方法,您可以做以下有趣的事情。

class IService {
public:
    char x;
};
Run Code Online (Sandbox Code Playgroud)

您的 IDE 将检测 IService 对象的堆栈损坏,但获取该输出

65
A
Run Code Online (Sandbox Code Playgroud)

是值得的,但是您会发现进行这种隐形继承会出现问题。

我也在使用 86x 编译器。所以基本上我的变量都排好了。举例来说,如果我在 Iservice 中的 int x 之上添加一个 int y,则该程序将输出无意义的内容。基本上它只能工作,因为我的类是二进制兼容的。