在 C++ 中传递函数指针

Posted

技术标签:

【中文标题】在 C++ 中传递函数指针【英文标题】:Passing function Pointers in C++ 【发布时间】:2010-09-29 00:21:07 【问题描述】:

我想做这个简单的代码工作。

#include <iostream>
#include <windows.h>


    void printSome (int i)
    
        std::cout << i << std::endl;
    

    void spawnThread (void (*threadName)(int i))
    
        CreateThread 
            (
                0,      // default security attributes
                0,          // use default stack size 
                (LPTHREAD_START_ROUTINE)threadName,  // thread function name
                (LPVOID)i,          // argument to thread function 
                0,          // use default creation flags 
                0       // returns the thread identifier 
            );  
    

    int main ()
    
        spawnThread(printSome(155));
    

我在windows上,使用vs。任何帮助都会非常感激。

【问题讨论】:

那么到底是什么问题? 【参考方案1】:

CreateThread 需要 2 个参数:指向要作为线程执行的函数的指针,以及将提供给线程的 DWORD 参数。您的 spawnThread() 函数只有 1 个参数(threadName);你认为它有 2 个参数,因为“i”,但这确实是“threadName”类型定义的一部分。 (您也可以省略“i”;也就是说,您不需要将参数命名为“threadName”。)

无论如何,鉴于您需要 2 个参数,请重新定义 spawnThread:

   void spawnThread(void (*threadEntryPoint)(int), int argument)
   
      CreateThread(0,0,
                   (LPTHREAD_START_ROUTINE)threadEntryPoint,
                   (LPVOID)argument,
                   0,0);
   

注意我没有命名 threadEntryPoint 的 int 参数;告诉编译器该函数必须有一个 int 参数就足够了。

然后调用它:

   spawnThread(printSome, 155);

无论如何,又快又脏,这会做你想做的。

第一次。

赖利。

【讨论】:

【参考方案2】:

就个人而言,我不会考虑像您尝试做的那样传递函数指针,就像 C++ 一样。那就是用 C++ 编写 C 代码

相反,我会将它封装在一个类中。最大的优势是您可以重写该类以拥有您想要的任意数量的成员,而不必每次都执行油腻的转换技巧来获取您的参数。

代码有点啰嗦,所以我把它推到最后。但它让你做的是这样的事情:

   class print_some : public basic_thread 
    private:
       int i;
    public:     
       print_some (int i) : i(i) ;
       action_callback () 
          std::cout << i << std::endl;
       
    
    int main () 
       print_some printer (155);
    

以下是我们其中一个类的一些摘录示例代码:

class basic_thread : 

public:
   basic_thread();
protected:
   unsigned long m_ThreadId;

   virtual void action_callback () ;

   // Internal routine used to bridge between OS callback format and 
   // action_callback. *Must* be static for the OS.
   static unsigned long __stdcall self_calling_callback (void *parameter);

...在 .cpp 中:

unsigned long __stdcall basic_thread::self_calling_callback (void *parameter) 
   if (parameter) 
      basic_thread * thread = reinterpret_cast<basic_thread *>(parameter);
      thread->action_callback();
   
   return 0; // The value returned only matters if someone starts calling GetExitCodeThread
             // to retrieve it.


basic_thread::basic_thread () 
   // Start thread.
   m_Handle = CreateThread(NULL,
                           0,
                           self_calling_callback,
                           (PVOID)this,
                           0,
                           &m_ThreadId );
   if( !IsHandleValid() )
      throw StartException("CreateThread() failed", GetLastError());


【讨论】:

【参考方案3】:

你不能在函数指针中传递参数信息;它必须单独通过。这正是 CreateThread 函数提供 void* 参数的原因,该参数可以指向您想要的任何内容。

此外,对于 C++ 应用程序,您应该 use _beginthread instead of CreateThread。

最后,您的程序很可能在线程运行之前终止。因此,您必须要么进入无限循环,要么使用 API 调用等待线程完成。

以下是使用WaitForSingleObject 阻塞直到线程完成的工作版本。

#include <iostream>
#include <process.h>
#include <windows.h>

void
printSome(int i)

    std::cout << i << std::endl;


HANDLE
spawnThread(void (*threadName)(int), int i)

    return (HANDLE) _beginthread((void (*)(void*)) threadName, 0, (LPVOID) i);      


int
main(int argc, char *argv[])

    HANDLE threadHandle;

    threadHandle = spawnThread(printSome, 155);
    WaitForSingleObject(threadHandle, INFINITE);

    return 0;


这里有一个更 C++/面向对象的方式来处理同样的情况:

#include <iostream>
#include <process.h>
#include <windows.h>

class Thread 
    static void proxy(void *arg)  (*(reinterpret_cast<Thread *> (arg)))(); 
    HANDLE thread_;

public:
    virtual ~Thread() 
    virtual void operator()() = 0;  
    void start()  thread_ = (HANDLE) _beginthread(Thread::proxy, 0, this);    
    void waitForExit()  WaitForSingleObject(thread_, INFINITE); 
;

class Printer : public Thread 
    int i_;

public:
    Printer(int i) : i_(i) 
    void operator()()  std::cout << i_ << std::endl; 
;

int
main(int argc, char *argv[])

    Printer p(155);

    p.start();
    p.waitForExit();

    return 0;

【讨论】:

很好的答案 - 除非您应该使用 _beginthread() 或 _beginthreadex() 而不是 CreateThread()。有关详细信息,请参阅***.com/questions/331536/…。 没错,我更新了答案。有太多的事情要解决! ;)【参考方案4】:

正如这里很多人已经提到的,你不能在一个参数中传递一个函数指针和它应该被调用的参数。

你的线路

    spawnThread(printSome(155));

“应该”(在 DWIM 世界中)表示“在带有参数 155 的单独线程上调用 printSome”。然而,这不是 C++ 理解它的方式。 C++ 看到“将在 155 上调用的 printSome 的结果作为参数传递给 spawnThread”。换句话说,步骤的顺序是:

以 155 作为参数调用 prinotSome。将其存储在临时内存中。 以临时内存的内容作为参数调用 spawnThread。

为了做到你真正的意思,你必须幽默 C++ 并将参数与函数分开。如何做到这一点已经在其他答案中解释过。简称:

callOnOtherThreadWithArgument(函数,整数);

【讨论】:

【参考方案5】:

您可以在此处阅读您的操作方法:http://www.newty.de/fpt/fpt.html

2.6 如何将函数指针作为参数传递?

您可以将函数指针作为 函数的调用参数。你需要 例如,如果您想通过 指向回调函数的指针。这 以下代码显示了如何通过 指向返回一个函数的指针 int 并接受一个浮点数和两个字符:

//------------------------------------------------------------------------------------
// 2.6 How to Pass a Function Pointer

// <pt2Func> is a pointer to a function which returns an int and takes a float and two char
void PassPtr(int (*pt2Func)(float, char, char))

   int result = (*pt2Func)(12, 'a', 'b');     // call using function pointer
   cout << result << endl;


// execute example code - 'DoIt' is a suitable function like defined above in 2.1-4
void Pass_A_Function_Pointer()

   cout << endl << "Executing 'Pass_A_Function_Pointer'" << endl;
   PassPtr(&DoIt);

【讨论】:

以上是关于在 C++ 中传递函数指针的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中传递函数指针

C++ 传递指针给函数

C++成员函数指针指向全局函数指针

如何在 C++ 中传递函数指针并在函数中进行比较?

是否传递指针参数,在 C++ 中按值传递?

如何将函数指针传递给成员函数c++?