有没有一种方法可以获得C++虚拟成员函数地址
Is there a way to get the C++ virtual member function address
我搜索了这篇文章:C++:获取函数virtual';地址';带有成员函数指针
为了测试虚拟成员函数是否通常位于对象的起始地址,我编写了以下代码:
#include <pwd.h>
#include <string.h>
#include <stdio.h>
class Base
{
public:
int mBase1;
char mBase2;
virtual void foo()
{
fprintf(stderr,"Base foo calledn");
}
};
class Child: public Base
{
public:
int cc;
virtual void foo()
{
fprintf(stderr,"Child foo called");
}
};
int main(int argc, char *argv[])
{
Base bb;
fprintf(stderr,"[mBase1 %p][mBase2 %p] [foo %p]n",&bb.mBase1,&bb.mBase2,&Base::foo);
return 0;
}
编译时,我收到一个警告:
test.cpp:30:88: warning ‘%p’ expects argument of type ‘void*’, but argument 5 has type ‘void (Base::*)()’ [-Wformat]
输出为:
[mBase1 0xbfc2ca38][mBase2 0xbfc2ca3c] [foo 0x1]
我认为它是有线的。
是否有任何"漂亮的方法"来获取成员函数(而不是静态成员函数地址?)。除了以下方法,还有其他优雅的方法吗?
typedef void (Base::*Foo)(); Foo f = &Base::foo();
为什么
&Base::foo
没有得到正确的C++成员地址?
为什么不&Base::foo获取正确的C++成员地址?
指向成员的指针与指针的类型不同(事实上,它们的偏移量比类型本身更多),特别是,它们不能转换为void*
(它们可以在GCC上转换,但可能是编译器扩展)。
参见C++11标准第8.3.3/3段:
指向成员的指针不应指向**类(9.4)的静态成员、具有引用类型的成员或"cv void"[注:另见5.3和5.5类型"pointer-to-member"不同于类型"pointer",也就是说,指向成员的指针仅通过指针-成员声明符语法声明,而从不通过指针-声明符语法来声明。C++中没有"引用成员"类型--尾注]
此外,第5.2.10/10段(关于reinterpret_cast<>
)定义了指向成员的指针的唯一可能转换如下:
如果T1和T2都是函数类型或都是对象类型,则"指向类型T1的X的成员的指针"类型的prvalue可以显式转换为不同类型的"指向类型T2的Y的成员的指示器"的prvalue。空成员指针值(4.11)被转换为目标类型的空成员指针数值。此转换的结果未指定,以下情况除外:
--将类型为"pointer-to-member function"的prvalue转换为不同的pointer-to-member函数类型并返回到其原始类型会生成原始的pointer--to-member值。
--将类型为"指向类型T1的X的数据成员的指针"的prvalue转换为类型"指向类型T2的Y的数据成员指针"(其中T2的对齐要求不比T1的对齐要求更严格)并返回到其原始类型产生原始的指向成员的指针值。
如前所述,指向成员的指针不是指针,它们转换为int或void*等类型通常没有意义。特别地,0x1很可能意味着对象vtable中的第一个或第二个条目。让我们考虑一下这个代码:
void (*Base::*test)() = &Base::foo
Child f;
f.*test();
对于第三行,编译器获得f的地址。将其转换为Base对象的地址,在本例中为NOOP)从该地址读取f的vtable地址(vtable通常是对象中的第一个数据项),然后添加两个地址1*sizeof(void*),并调用该地址处的函数,该函数在很大程度上相当于这个C:
typedef void (*FnPtr)();
FnPtr *vtable=*(FnPtr **)&(Base &)f;
(*(vtable[(int)test]))(); or (*(vtable[(int)test - 1]))();
这是唯一的假设,可能是真的确切版本的编译器。即使是未来的编译器版本也不能保证可移植性。
为什么不&Base::foo获取正确的C++成员地址?
Base::foo不是一个静态方法。没有属于Base的foo。我想知道[foo 0x1]是什么意思(例如:如果整件事没有多大意义,为什么是0x1)?
- 虚拟成员函数的定义是否强制在同一转换单元中动态初始化静态数据成员?
- 钻石继承虚拟成员铸造与指针
- 如果我必须覆盖非虚拟成员函数怎么办
- c++\CLI dll包装器,用于调用c++类中的虚拟成员
- 非虚拟成员函数是否可以使用模板参数?
- 如何将已实现的虚拟成员函数作为参数传递
- 调用虚拟成员类的方法
- 睡眠影响 std::thread 调用哪个虚拟成员函数?
- GTEST:嘲笑非虚拟成员函数
- 使SDL称为纯虚拟成员作为事件回调
- 在C中使用具有虚拟成员(即非POD)的C++结构
- 虚拟和非虚拟成员函数的调用方式有什么区别?
- 默认情况下是虚拟成员函数
- 是否可以在不重写派生类中记录虚拟成员?
- 为什么在已删除的指针上调用非虚拟成员函数是未定义的行为
- C++标准是否保证了没有虚拟成员函数的类类型的大小
- 使用虚拟成员从课堂制作 POD
- C++合成的move构造函数如何受到volatile和虚拟成员的影响
- 指向虚拟成员功能
- 在非构造"object"上调用非虚拟成员函数是否定义良好?