关于一个访问虚函数地址语义问题
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? 在C++中,对象的虚函数通常是通过虚函数表(vtable)来实现的。一个对象的vtable是一个函数指针的数组,其中每个函数指针对应于对象的一个虚函数。vtable的具体实现可能因编译器而异,但通常,当你创建一个对象时,编译器会自动在该对象中插入一个指向其vtable的指针。
从你的代码中,我假设Test是一个含有虚函数a的类。然后你试图手动通过对内存的操作来访问这个虚函数a的地址。在你的第二段代码中,你试图获取tptr(指向Test对象test的指针)的vtable中第一个函数的地址。
关于你的问题,我认为你在第二段代码中遇到分段错误的原因可能是,你在操作指针时,不小心访问到了不应该访问的内存区域。这可能是因为你的代码假设了某种特定的内存布局或者vtable的实现,而这种假设在你的环境中并不成立。例如,你可能假设Test对象的第一个字节就是指向其vtable的指针,但实际上可能并不是这样。
你可能需要使用一些更复杂的技术,如RTTI(运行时类型信息)或者dynamic_cast,来安全地获取和调用虚函数的地址。但是,我建议你不要试图手动操作vtable或者内存,因为这样很容易出错,而且会使你的代码变得难以理解和维护。如果你需要调用一个对象的虚函数,你应该直接通过对象或者指向对象的指针来调用它,而不是试图手动找到这个函数在内存中的位置。
更一般地说,如果你需要在运行时获取和调用一个对象的虚函数的地址,那么你可能需要重新考虑你的设计。在大多数情况下,你应该能够通过使用正确的继承和多态来实现你需要的功能,而无需手动操作内存。如果你觉得你需要手动操作vtable,那么你可能需要寻求一种更好的解决方案。 isdkz 发表于 2023-5-31 11:43
在C++中,对象的虚函数通常是通过虚函数表(vtable)来实现的。一个对象的vtable是一个函数指针的数组,其中 ...
懂了,任何看不见的东西,不能做逻辑假设。忘了这个点了。 isdkz 发表于 2023-5-31 11:43
在C++中,对象的虚函数通常是通过虚函数表(vtable)来实现的。一个对象的vtable是一个函数指针的数组,其中 ...
我要访问虚函数的地址,是因为在学习“单纯类在不单纯时引发的虚函数调用问题”课题时,想要看到虚函数具体的改变。比如类中有虚函数表指针,而用memset进行构造函数初始化的时候,会把虚函数表指针的数据也清除。并不是因为我的解决方案有问题,需要去修改虚函数。感谢解答,豁然开朗。
页:
[1]