鱼C论坛

 找回密码
 立即注册
查看: 1016|回复: 3

[已解决]关于一个访问虚函数地址语义问题

[复制链接]
发表于 2023-5-31 11:39:29 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
        Test test;
        Test* tptr = &test;
        std::cout << (void*)(&tptr->a) << std::endl;
        std::cout << (void*)((void(*)()) * ((int*)(*((int*)&test)) + 0)) << std::endl;
    第二个输出虚函数的地址是正确的。
    如果这么写:
std::cout << (void*)((void(*)()) * ((int*)(*((int*)tptr)) + 0)) << std::endl;
    就是分段错误。
    这是怎么回事?难道还要用 dynamic?
最佳答案
2023-5-31 11:43:59
在C++中,对象的虚函数通常是通过虚函数表(vtable)来实现的。一个对象的vtable是一个函数指针的数组,其中每个函数指针对应于对象的一个虚函数。vtable的具体实现可能因编译器而异,但通常,当你创建一个对象时,编译器会自动在该对象中插入一个指向其vtable的指针。

从你的代码中,我假设  Test  是一个含有虚函数  a  的类。然后你试图手动通过对内存的操作来访问这个虚函数  a  的地址。在你的第二段代码中,你试图获取  tptr  (指向  Test  对象  test  的指针)的vtable中第一个函数的地址。

关于你的问题,我认为你在第二段代码中遇到分段错误的原因可能是,你在操作指针时,不小心访问到了不应该访问的内存区域。这可能是因为你的代码假设了某种特定的内存布局或者vtable的实现,而这种假设在你的环境中并不成立。例如,你可能假设  Test  对象的第一个字节就是指向其vtable的指针,但实际上可能并不是这样。

你可能需要使用一些更复杂的技术,如RTTI(运行时类型信息)或者dynamic_cast,来安全地获取和调用虚函数的地址。但是,我建议你不要试图手动操作vtable或者内存,因为这样很容易出错,而且会使你的代码变得难以理解和维护。如果你需要调用一个对象的虚函数,你应该直接通过对象或者指向对象的指针来调用它,而不是试图手动找到这个函数在内存中的位置。

更一般地说,如果你需要在运行时获取和调用一个对象的虚函数的地址,那么你可能需要重新考虑你的设计。在大多数情况下,你应该能够通过使用正确的继承和多态来实现你需要的功能,而无需手动操作内存。如果你觉得你需要手动操作vtable,那么你可能需要寻求一种更好的解决方案。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2023-5-31 11:43:59 | 显示全部楼层    本楼为最佳答案   
在C++中,对象的虚函数通常是通过虚函数表(vtable)来实现的。一个对象的vtable是一个函数指针的数组,其中每个函数指针对应于对象的一个虚函数。vtable的具体实现可能因编译器而异,但通常,当你创建一个对象时,编译器会自动在该对象中插入一个指向其vtable的指针。

从你的代码中,我假设  Test  是一个含有虚函数  a  的类。然后你试图手动通过对内存的操作来访问这个虚函数  a  的地址。在你的第二段代码中,你试图获取  tptr  (指向  Test  对象  test  的指针)的vtable中第一个函数的地址。

关于你的问题,我认为你在第二段代码中遇到分段错误的原因可能是,你在操作指针时,不小心访问到了不应该访问的内存区域。这可能是因为你的代码假设了某种特定的内存布局或者vtable的实现,而这种假设在你的环境中并不成立。例如,你可能假设  Test  对象的第一个字节就是指向其vtable的指针,但实际上可能并不是这样。

你可能需要使用一些更复杂的技术,如RTTI(运行时类型信息)或者dynamic_cast,来安全地获取和调用虚函数的地址。但是,我建议你不要试图手动操作vtable或者内存,因为这样很容易出错,而且会使你的代码变得难以理解和维护。如果你需要调用一个对象的虚函数,你应该直接通过对象或者指向对象的指针来调用它,而不是试图手动找到这个函数在内存中的位置。

更一般地说,如果你需要在运行时获取和调用一个对象的虚函数的地址,那么你可能需要重新考虑你的设计。在大多数情况下,你应该能够通过使用正确的继承和多态来实现你需要的功能,而无需手动操作内存。如果你觉得你需要手动操作vtable,那么你可能需要寻求一种更好的解决方案。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-31 11:49:19 | 显示全部楼层
isdkz 发表于 2023-5-31 11:43
在C++中,对象的虚函数通常是通过虚函数表(vtable)来实现的。一个对象的vtable是一个函数指针的数组,其中 ...

懂了,任何看不见的东西,不能做逻辑假设。忘了这个点了。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2023-5-31 11:57:07 | 显示全部楼层
isdkz 发表于 2023-5-31 11:43
在C++中,对象的虚函数通常是通过虚函数表(vtable)来实现的。一个对象的vtable是一个函数指针的数组,其中 ...

我要访问虚函数的地址,是因为在学习“单纯类在不单纯时引发的虚函数调用问题”课题时,想要看到虚函数具体的改变。比如类中有虚函数表指针,而用memset进行构造函数初始化的时候,会把虚函数表指针的数据也清除。并不是因为我的解决方案有问题,需要去修改虚函数。感谢解答,豁然开朗。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2024-12-24 21:29

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表