我不小心调用了一个没有自己类对象的成员函数.但这是怎么回事呢
I accidentally called a member function without own class object. But how does this work?
这是我的代码。
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;
}
我不明白这是怎么回事。我没有继承IService,也没有创建X_Service对象,但它可以工作。有人能解释一下吗
您的困惑可能源于误解,因为某些东西编译和运行时不会崩溃,所以它"正常工作"。事实并非如此。
有很多方法可以打破语言规则,仍然编写编译和运行的代码。通过在这里使用reinterpret_cast
并进行无效的强制转换,您违反了语言规则,并且您的程序具有未定义的行为。
这意味着它看起来可以工作,可以崩溃,也可以做一些与你预期完全不同的事情。
在您的情况下,它似乎可以工作,但它仍然是UB,并且代码无效。
在后台,编译器会将所有这些函数转换为机器代码,基本上只是跳转到内存中的某些地址,然后执行存储在那里的命令。
成员函数只是一个函数,除了局部变量和参数外,还有一块存储类对象地址的内存。当您使用this
关键字时,该内存会保存您正在访问的地址。
如果在错误的对象或nullptr上调用成员函数,那么基本上只会使this
指针指向无效的对象。
您的函数无法访问this
,这就是您的程序不会爆炸的原因。
也就是说,这仍然是未定义的行为,任何事情都可能发生。
所以,我玩得很开心,并对代码进行了一些操作。这也是一个经验答案。这种做法有很多陷阱会导致堆栈损坏,所以我对代码做了一些更改,使其成为不会发生堆栈损坏的地方,但有点显示它发生了什么。
#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;
}
因此,从一开始,auto
就赋予了您制作无类型安全指针void (IService::*)()
的能力——对象本身的实例也是this->
,而不管您从哪个类的哪个成员函数隐形继承。唯一的问题是,实例的第一个变量是基于从中隐式继承的类的第一个参数来解释的,如果类型不同,可能会导致堆栈损坏。
为了获得很酷的输出,但不可避免地会导致堆栈损坏,您可以做以下有趣的事情。
class IService {
public:
char x;
};
您的IDE将检测到IService对象的堆栈损坏,但会得到的输出
65
A
这是值得的,但你会看到,做这种隐形继承会出现问题。
我也在使用86x编译器。所以基本上我的变量都排好了。举个例子,如果我在Iservice中的int x之上添加一个int y,这个程序就会输出一些废话。基本上,它之所以有效,是因为我的类是二进制兼容的。
当您reinterpret_cast
一个函数或成员函数指针指向不同类型时,您永远不允许调用结果指针,除非您先将其强制转换回其原始类型并通过该类型进行调用。
违反此规则会导致未定义的行为。这意味着你失去了任何语言对程序将以任何特定方式运行的保证,而没有来自特定编译器的额外保证。
reinterpret_cast
通常是危险的,因为它完全绕过了类型系统。如果您使用它,您需要始终通过查看语言规则来验证自己,即强制转换和结果的使用方式是否定义良好。reinterpret_cast
告诉编译器你知道你在做什么,你不希望任何警告或错误,即使结果是无关紧要的。
- 找不到成员对象:没有名为get_event()的成员,也处理多态性和向量
- 在运行时有条件地删除类成员或跳过调用该成员对象的构造函数
- C++是否有定义的方法来传递指向类的成员对象的成员函数的指针
- (2 问题)"类"类型重新定义(即使 #pragma 一次),以及静态函数内的静态成员对象初始化?
- 声明成员对象而不调用其默认构造函数
- 指向成员对象的指针 - 中断线程
- 是否有更好的方法来封装成员对象可以访问的共享存储池?
- 应该在成员对象上调用析构函数
- 调用成员对象的构造函数
- 将 const 类型引用对象注册为类成员对象C++
- 修改类 c++ 中的成员对象
- 从成员对象调用方法
- 从对象调用成员对象,错误:引用非常量值的初始值必须是左值
- 构造函数,成员对象
- 不能使外部类成为内部类内的成员对象
- 使用从另一个类继承的类的对象初始化成员对象
- 如何避免需要在初始化列表中初始化成员对象
- 初始化具有参数的类成员对象的正确方法
- 将指针添加到成员对象中的指针动态阵列
- C 将成员对象函数分配给类成员功能