在c++中,何时以及如何使用回调函数?

编辑: 我想看一个简单的例子来写一个回调函数。


当前回答

在c++中并没有明确的回调函数的概念。回调机制通常通过函数指针、函子对象或回调对象实现。程序员必须显式地设计和实现回调功能。

根据反馈进行编辑:

尽管这个答案收到了负面的反馈,但它并没有错。我会试着更好地解释我的观点。

C和c++拥有实现回调函数所需的一切。实现回调函数最常见和最简单的方法是将函数指针作为函数参数传递。

However, callback functions and function pointers are not synonymous. A function pointer is a language mechanism, while a callback function is a semantic concept. Function pointers are not the only way to implement a callback function - you can also use functors and even garden variety virtual functions. What makes a function call a callback is not the mechanism used to identify and call the function, but the context and semantics of the call. Saying something is a callback function implies a greater than normal separation between the calling function and the specific function being called, a looser conceptual coupling between the caller and the callee, with the caller having explicit control over what gets called. It is that fuzzy notion of looser conceptual coupling and caller-driven function selection that makes something a callback function, not the use of a function pointer.

例如,IFormatProvider的. net文档说“GetFormat是一个回调方法”,即使它只是一个普通的接口方法。我认为没有人会认为所有的虚方法调用都是回调函数。使GetFormat成为回调方法的不是它如何传递或调用的机制,而是调用方选择调用哪个对象的GetFormat方法的语义。

一些语言包含带有显式回调语义的特性,通常与事件和事件处理相关。例如,c#的事件类型的语法和语义显式地围绕回调的概念设计。Visual Basic有它的Handles子句,它显式地将一个方法声明为回调函数,同时抽象了委托或函数指针的概念。在这些情况下,回调的语义概念集成到语言本身中。

另一方面,C和c++几乎没有显式地嵌入回调函数的语义概念。机制在那里,集成的语义不在那里。你可以很好地实现回调函数,但是为了获得更复杂的、包含显式回调语义的东西,你必须在c++提供的基础上构建它,比如Qt对它们的信号和插槽所做的事情。

简而言之,c++拥有实现回调所需的一切,通常使用函数指针非常简单。它没有的是语义特定于回调的关键字和特性,比如raise、emit、Handles、event +=等。如果您来自具有这些类型的元素的语言,那么c++中的本机回调支持将感觉很中性。

其他回答

回调函数是传递给例程的方法,在某个时刻被传递给它的例程调用。

这对于开发可重用软件非常有用。例如,许多操作系统API(如Windows API)大量使用回调。

例如,如果你想处理文件夹中的文件,你可以用你自己的例程调用一个API函数,并且你的例程在指定的文件夹中对每个文件运行一次。这使得API非常灵活。

在c++中并没有明确的回调函数的概念。回调机制通常通过函数指针、函子对象或回调对象实现。程序员必须显式地设计和实现回调功能。

根据反馈进行编辑:

尽管这个答案收到了负面的反馈,但它并没有错。我会试着更好地解释我的观点。

C和c++拥有实现回调函数所需的一切。实现回调函数最常见和最简单的方法是将函数指针作为函数参数传递。

However, callback functions and function pointers are not synonymous. A function pointer is a language mechanism, while a callback function is a semantic concept. Function pointers are not the only way to implement a callback function - you can also use functors and even garden variety virtual functions. What makes a function call a callback is not the mechanism used to identify and call the function, but the context and semantics of the call. Saying something is a callback function implies a greater than normal separation between the calling function and the specific function being called, a looser conceptual coupling between the caller and the callee, with the caller having explicit control over what gets called. It is that fuzzy notion of looser conceptual coupling and caller-driven function selection that makes something a callback function, not the use of a function pointer.

例如,IFormatProvider的. net文档说“GetFormat是一个回调方法”,即使它只是一个普通的接口方法。我认为没有人会认为所有的虚方法调用都是回调函数。使GetFormat成为回调方法的不是它如何传递或调用的机制,而是调用方选择调用哪个对象的GetFormat方法的语义。

一些语言包含带有显式回调语义的特性,通常与事件和事件处理相关。例如,c#的事件类型的语法和语义显式地围绕回调的概念设计。Visual Basic有它的Handles子句,它显式地将一个方法声明为回调函数,同时抽象了委托或函数指针的概念。在这些情况下,回调的语义概念集成到语言本身中。

另一方面,C和c++几乎没有显式地嵌入回调函数的语义概念。机制在那里,集成的语义不在那里。你可以很好地实现回调函数,但是为了获得更复杂的、包含显式回调语义的东西,你必须在c++提供的基础上构建它,比如Qt对它们的信号和插槽所做的事情。

简而言之,c++拥有实现回调所需的一切,通常使用函数指针非常简单。它没有的是语义特定于回调的关键字和特性,比如raise、emit、Handles、event +=等。如果您来自具有这些类型的元素的语言,那么c++中的本机回调支持将感觉很中性。

回调函数是C标准的一部分,因此也是c++的一部分。但如果您正在使用c++,我建议您使用观察者模式:http://en.wikipedia.org/wiki/Observer_pattern

Scott Meyers举了一个很好的例子:

class GameCharacter;
int defaultHealthCalc(const GameCharacter& gc);

class GameCharacter
{
public:
  typedef std::function<int (const GameCharacter&)> HealthCalcFunc;

  explicit GameCharacter(HealthCalcFunc hcf = defaultHealthCalc)
  : healthFunc(hcf)
  { }

  int healthValue() const { return healthFunc(*this); }

private:
  HealthCalcFunc healthFunc;
};

我认为这个例子说明了一切。

std::function<>是编写c++回调函数的“现代”方式。

C语言中也有回调的方法:函数指针

// Define a type for the callback signature,
// it is not necessary but makes life easier

// Function pointer called CallbackType that takes a float
// and returns an int
typedef int (*CallbackType)(float);

void DoWork(CallbackType callback)
{
  float variable = 0.0f;
  
  // Do calculations
  
  // Call the callback with the variable, and retrieve the
  // result
  int result = callback(variable);

  // Do something with the result
}

int SomeCallback(float variable)
{
  int result;

  // Interpret variable

  return result;
}

int main(int argc, char ** argv)
{
  // Pass in SomeCallback to the DoWork
  DoWork(&SomeCallback);
}

现在,如果你想将类方法作为回调函数传入,对这些函数指针的声明会有更复杂的声明,例如:

// Declaration:
typedef int (ClassName::*CallbackType)(float);

// This method performs work using an object instance
void DoWorkObject(CallbackType callback)
{
  // Class instance to invoke it through
  ClassName objectInstance;

  // Invocation
  int result = (objectInstance.*callback)(1.0f);
}

//This method performs work using an object pointer
void DoWorkPointer(CallbackType callback)
{
  // Class pointer to invoke it through
  ClassName * pointerInstance;

  // Invocation
  int result = (pointerInstance->*callback)(1.0f);
}

int main(int argc, char ** argv)
{
  // Pass in SomeCallback to the DoWork
  DoWorkObject(&ClassName::Method);
  DoWorkPointer(&ClassName::Method);
}