【问题标题】:Function pointer as a member of a class作为类成员的函数指针
【发布时间】:2013-08-16 06:46:02
【问题描述】:

关于 C++ 中的函数指针,类函数和全局函数有什么区别?我在问,因为如果函数是类成员,Windows CreateThread 方法似乎不接受线程代码进入的函数。

当它是一个全局方法时,我可以将函数(线程代码进入)传递给 CreateThread 消息,但是一旦我将它设为类的成员,我就会收到错误“[方法布局]类型的参数是与 LPTHREAD_START_ROUTINE 类型的参数不兼容”。 ClassName::* 现在在中间;这对它有影响吗?

解决方法是什么?

【问题讨论】:

  • C++11 中的 lambdas 或之前的 boost::bind - 发布有问题的代码,我们将向您展示如何
  • 可能的线程函数的签名必须完全匹配,Win32-API 是纯 C API,不适用于 C++ 类。
  • @doctorlove, 结果与CreateThread取的函数指针不兼容。
  • 在 C++11 中,您可能会考虑切换到标准线程库。然后它类似于thread([this]{member();}),而不是正确答案中的胡言乱语,具有便携性作为奖励。
  • @MikeSeymour,好点,我不知道为什么我没有想到。我会把它放在一个显眼的地方。

标签: c++ function class pointers


【解决方案1】:

成员函数指针 (DWORD(WINAPI Foo::*)(LPVOID)) 与函数指针 (DWORD(WINAPI *)(LPVOID)) 的类型不同。成员函数有一个隐藏的this 参数,导致签名不匹配。

最简单的方法是使用 C++11 的 <thread> 标头:

struct Foo {
    void threadProc() {}
};

int main() {
    Foo foo;
    std::thread t{&Foo::threadProc, foo, /*other arguments to threadProc*/};
    t.join();
}

如果必须使用CreateThread,请使用void * 参数来传递实例:

struct Foo {
    DWORD threadProc() {...}
};

extern "C" DWORD WINAPI proxyThreadProc(LPVOID userData) {
    auto foo = static_cast<Foo *>(userData);
    if (foo) {foo->threadProc();}
}

int main() {
    Foo foo;
    CreateThread(..., proxyThreadProc, &foo, ...);
}

你的类中的那个现在几乎可以是你想要的任何东西(比如std::function)并且仍然可以工作,只要它在代理过程中使用正确的参数调用。

【讨论】:

  • 值得注意的是,如果proxyThreadProc 是Foo 的静态成员函数,这也会起作用。在这种情况下,这有时是一种能够使用私有成员函数的好方法。
  • 函数后不应该在 'extern "C"' 后跟一个 '{' 和一个结束 '}' 吗?
  • @MagnusHoff,这对我来说也很新鲜,但read this。
  • @Kevin,大括号仅用于包含多个。
  • @chris 哦。谢谢。相关引用:“请注意,在 C++ 中实现的 C 回调函数必须是 extern "C"。它似乎在类中作为静态函数工作,因为类静态函数通常使用与 C 函数相同的调用约定。但是,做这是一个等待发生的错误(请参阅下面的 cmets),所以请不要 - 改为通过 extern "C" 包装器。” (Interesting discussion on the topic)
【解决方案2】:

是的,正如@chris 所说,有一个隐藏指针 this 将在参数末尾连接。线程执行该操作时,不知道匹配到最后一个参数位置的指针,完成后无法恢复该函数的堆,所以禁止使用类的非静态成员函数驱动一个线程函数,除了类的全局函数或静态成员函数。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-07-27
    • 2013-06-06
    • 2014-11-08
    相关资源
    最近更新 更多