【问题标题】:Value of Pointer to Non-Static Member function指向非静态成员函数的指针的值
【发布时间】:2013-07-24 21:07:45
【问题描述】:

我试图了解用于实现指向非静态成员函数的指针的底层机制。我正在寻找一个类似于 vtbl(多态虚拟表)如何在大局中工作的答案,而不必担心编译器之间可能会有所不同的细节。

例子:

#include <stdio.h>

class A {
public:
    int i;
    int j;
    void foo(void)  {  };
};


int main () 
{
    int A::*ptr_j = &A::j;
    void (A::*ptr_f)(void) = &A::foo;
    printf("Foo::j   pointer to data member %p\r\n", ptr_j);  
    printf("Foo::foo pointer to function member %p\r\n", ptr_f);
}

结果是

Foo::j指向数据成员0x4的指针

Foo::foo指向函数成员0x804844c的指针

来自“Stroustrup 的 C++ 编程语言”,

指向成员的指针...更像是结构的偏移量或数组的索引...

对于数据成员,我了解 Pointer-To-Member Foo::j 或多或少等同于 offsetOf(Foo, j)。在我的宿主环境中使用 gcc 编译器时的值为 4,与 offsetOf(Foo, j) 为 4 匹配。

对于函数成员,返回值为0x804844c。这是属于全局数据区的某个地址(加载类的地方?)

所以我的问题是:

地址0x804844c的“对象”是什么。

  1. 不能是简单的offsetOf(),因为这是一个很大的偏移量。
  2. 它不能是 vtbl 的地址(或 vtbl 中条目的地址),因为我认为 vbtl 是与实例化对象相关联的实体,而不是与类相关联。
  3. 不能是加载函数实现代码的地址。因为相同的指针在与派生对象一起应用时可以表现出多态性。

那么地址0x804844c处的对象是什么,在应用-&gt;*.*运算符时,它在将指向成员函数的指针转换为实际函数地址的作用是什么?

【问题讨论】:

  • 函数不是 C++ 语言标准使用该术语的意义上的“对象”。请注意,成员函数通常实现为带有附加参数的普通函数(对象变为this)。在这些实现中,它们不驻留在类实例本身中,而是与代码段中的其他(免费)函数一起。
  • “它不能是加载函数实现代码的地址。因为相同的指针在与派生对象一起应用时可以表现出多态性。” 参见,例如this answer

标签: c++


【解决方案1】:

您不能使用printf%p 转换说明符打印指向成员对象的值。它们不一定是常规指针。 %p 说明符需要 void * 值。严格来说,您甚至无法使用%p 便携式打印常规函数指针,因为这需要将函数指针转换为void *

指向成员的指针类型不一定适合一个可以保存地址的机器字。它们可以是具有多个字段的数据结构。

我相信 vbtl 是与实例化对象相关联的实体,而不是与类相关联。

这是不正确的。虚拟表是静态结构,实例只指向它们。给定类的所有实例共享一个指向同一个表的指针。

指向非静态成员函数的指针在一方面更简单,因为它不必处理类实例中任意数据成员的偏移量。但是,指向非静态成员函数的指针由于需要支持虚函数而变得复杂,并且通过这样的指针调用的代码不知道也不关心它是调用虚函数还是非虚函数.

指向成员函数的指针的一种实现策略涉及到 thunk:编译器生成的代码片段,它们执行正确的逻辑,以正确的方式进行调用。然后指向成员的指针可以指向 thunk。 thunk 知道在 this 对象中的何处找到 vtable 指针,以及 vtable 中的哪个偏移量是最终要调用的函数。

【讨论】:

    猜你喜欢
    • 2018-01-02
    • 2010-11-02
    • 2020-12-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-28
    相关资源
    最近更新 更多