【问题标题】:Call a member function with bare function pointer使用裸函数指针调用成员函数
【发布时间】:2011-03-10 03:06:24
【问题描述】:

如果你有一个对象和一个指向成员的裸函数指针,那么调用成员函数的最佳方法是什么?本质上我想用thiscall调用约定来调用函数指针。

背景:我正在动态查找共享库中的符号,获取工厂函数指针和指向我要调用的某个成员函数的指针。成员函数本身不是虚拟的。我无法控制共享库,我只有二进制文件。

例子:

typedef void * (*GenericFptr)();
GenericFptr lookup(const char *);

class CFoo;

GenericFptr factoryfn(lookup("CFoo factory function"));
CFoo *foo = reinterpret_cast<CFoo *>(factoryfn());

GenericFptr memberfn(lookup("CFoo member function"));

// now invoke memberfn on foo

目前我正在使用union 将函数指针转换为指向成员函数的指针。它很丑陋,并创建了对编译器实现细节的依赖:

class CFoo {
  public: 
  void *dummy() { return 0; }
};
typedef void * (CFoo::*FooMemberPtr)();

union {
  struct {
    // compiler-specific layout for pointer-to-member
    void *x, *y;
    GenericFptr ptr;
  } fnptr;
  FooMemberPtr memberfn;
} f;

f.memberfn = &CFoo::dummy; // init pointer-to-member
f.fnptr.ptr = memberfn;    // rewrite pointer

void *result = (foo->*f.memberfn)();

【问题讨论】:

  • 成员函数的符号是​​如何出现在共享对象中的?当我尝试这样做时,不会发布非虚拟成员函数符号。

标签: c++ function-pointers member-function-pointers


【解决方案1】:

指向成员函数的指针不能存储在指向函数的指针中,因为它需要更多信息(例如,在多重继承的情况下,可能必须在调用之前对 this 应用偏移量)。所以你不能不了解实现细节。

如果您想要可移植,最简单的方法是让您的库提供执行成员调用的包装函数。

【讨论】:

  • 谢谢。我知道足够的实现细节来使联合技巧起作用,但我不想这样做。我无法触及库本身,因为它已经部署到数亿个实例。
  • 是否可以添加第二个提供包装器的库?你制定的问题没有标准的解决方案,所以你必须改变你的方法。在不了解整个上下文的情况下,很难提出建议。
【解决方案2】:

不幸的是,成员函数指针比标准函数指针包含更多信息,当您获得标准函数指针时,将其转换为成员函数指针实际上会试图凭空生成额外的数据。

我不认为有任何可移植的方式来做你正在尝试的事情,尽管如果联合似乎工作你可能会侥幸逃脱。同样,对于您希望用于构建预兆的每个编译器,您需要了解这些方法的表示和调用约定。

如果您知道成员函数的名称,为什么不能只使用foo-&gt;dummy() ?否则,查找函数需要提供完整的成员函数指针,或者库必须提供一个 C 包装接口,其中包含可以传递 this 指针的普通函数。

【讨论】:

  • 谢谢。直接调用函数不是一种选择,因为我无法在编译时链接到库。并且查找功能是底层操作系统提供的,不能轻易替换。
  • 我认为你可能错了,马克。拉拉托有 2 分。给定一个指向实例的指针和一个成员函数的地址,就很可能在实例上调用成员函数。对于虚函数,甚至可能在具有虚函数的类中定义的非虚函数,这显然是不平凡的。普通类上的非虚拟函数应该很容易,但是可移植应用程序仍然需要知识或某些编译器中的类型。我将在 GCC 中编写一个最简单的示例。
【解决方案3】:

以下两个链接提供了见解和可能的解决方案。请注意,使用 this 参数调用成员函数指针通常不起作用,因为您必须考虑虚拟方法、多重继承和虚拟继承。

http://www.codeproject.com/KB/cpp/FastDelegate.aspx

http://www.codeproject.com/KB/cpp/ImpossiblyFastCppDelegate.aspx

【讨论】:

    【解决方案4】:

    根据下面的答案,它在 GCC 中是可行的,但不可移植:

    https://stackoverflow.com/a/5067992/705086

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-12-16
      • 1970-01-01
      • 2011-07-10
      • 2016-08-17
      • 2010-12-01
      相关资源
      最近更新 更多