函数指针有什么意义?

gra*_*amm 85 c c++ pointers function c++-faq

我很难看到函数指针的实用程序.我想它在某些情况下可能是有用的(毕竟它们存在),但我想不出使用函数指针更好或不可避免的情况.

你能举出一些好用函数指针的例子(在C或C++中)吗?

sbi*_*sbi 106

大多数示例归结为回调:您调用一个函数f()传递另一个函数的地址g(),并f()调用g()某些特定任务.如果您传递f()h()相反的地址,f()则会回拨h().

基本上,这是一种参数化函数的方法:其行为的某些部分不是硬编码的f(),而是进入回调函数.f()调用者可以通过传递不同的回调函数来使行为不同.经典qsort()来自C标准库,它将其排序标准作为指向比较函数的指针.

在C++中,这通常使用函数对象(也称为仿函数)来完成.这些是重载函数调用操作符的对象,因此您可以像调用函数一样调用它们.例:

class functor {
  public:
     void operator()(int i) {std::cout << "the answer is: " << i << '\n';}
};

functor f;
f(42);
Run Code Online (Sandbox Code Playgroud)

这背后的想法是,与函数指针不同,函数对象不仅可以携带算法,还可以携带数据:

class functor {
  public:
     functor(const std::string& prompt) : prompt_(prompt) {}
     void operator()(int i) {std::cout << prompt_ << i << '\n';}
  private:
     std::string prompt_;
};

functor f("the answer is: ");
f(42);
Run Code Online (Sandbox Code Playgroud)

另一个优点是,与通过函数指针调用相比,有时更容易内联调用函数对象.这就是为什么在C++中排序有时比在C中排序更快的原因.

  • +1这是唯一的例子,实际**代码**! (8认同)
  • @krynr:虚拟函数是仅指向编译器实现者的函数指针,如果您必须询问它们的优点,则可能(希望如此!)不太可能需要实现编译器的虚拟函数机制。 (2认同)

Maw*_*awg 39

好吧,我通常在跳转表中使用它们(专业)(另请参阅此StackOverflow问题).

跳转表通常(但不是唯一地)用于有限状态机中以使它们被数据驱动.而不是嵌套的开关/案例

  switch (state)
     case A:
       switch (event):
         case e1: ....
         case e2: ....
     case B:
       switch (event):
         case e3: ....
         case e1: ....
Run Code Online (Sandbox Code Playgroud)

你可以制作一个2d数组或函数指针,然后调用 handleEvent[state][event]


And*_*rey 24

例子:

  1. 自定义排序/搜索
  2. 不同的模式(如战略,观察者)
  3. 回调


Car*_*icz 10

函数指针有用性的"经典"示例是C库qsort()函数,它实现了快速排序.为了对用户可能提出的任何和所有数据结构进行通用,它需要几个指向可排序数据的void指针和一个指向知道如何比较这些数据结构的两个元素的函数的指针.这允许我们创建我们的工作选择功能,事实上甚至允许在运行时选择比较功能,例如用于升序或降序排序.


Ric*_*ich 6

同意上述所有内容,加上....当您在运行时动态加载DLL时,您需要函数指针来调用函数.


Mat*_* M. 6

我要反对现在的情况.

在C中,函数指针是实现自定义的唯一方法,因为没有OO.

在C++中,您可以使用函数指针或函子(函数对象)获得相同的结果.

由于它们的对象性质,仿函数比原始函数指针具有许多优点,特别是:

  • 他们可能会出现几次重载 operator()
  • 他们可以拥有现有变量的状态/引用
  • 它们可以在现场(lambdabind)建造

我个人更喜欢函子指针(尽管有样板代码),主要是因为函数指针的语法很容易变得毛茸茸(来自函数指针教程):

typedef float(*pt2Func)(float, float);
  // defines a symbol pt2Func, pointer to a (float, float) -> float function

typedef int (TMyClass::*pt2Member)(float, char, char);
  // defines a symbol pt2Member, pointer to a (float, char, char) -> int function
  // belonging to the class TMyClass
Run Code Online (Sandbox Code Playgroud)

我唯一一次见过函数指针,而函数指针在Boost.Spirit中没有.他们完全滥用语法将任意数量的参数作为单个模板参数传递.

 typedef SpecialClass<float(float,float)> class_type;
Run Code Online (Sandbox Code Playgroud)

但由于可变参数模板和lambdas即将到来,我不确定我们将在纯C++代码中使用函数指针.

  • @krynr:我会礼貌地不同意.重要的是你*看*和*type*,这是你使用的语法.你在幕后如何运作并不重要:这就是**抽象**的意义所在. (2认同)

小智 5

在C中,经典用法是qsort函数,其中第四个参数是指向用于在排序中执行排序的函数的指针.在C++中,人们倾向于使用仿函数(看起来像函数的对象)来做这种事情.

  • @KennyTM:我在C标准库中指出了唯一的其他实例.您引用的示例是第三方库的一部分. (2认同)

myr*_*ack 5

我最近使用函数指针来创建一个抽象层.

我有一个用纯C编写的程序,可以在嵌入式系统上运行.它支持多种硬件变体.根据我运行的硬件,它需要调用某些功能的不同版本.

在初始化时,程序会计算出运行的硬件并填充函数指针.程序中的所有高级例程都只调用指针引用的函数.我可以添加对新硬件变体的支持,而无需触及更高级别的例程.

我曾经使用switch/case语句来选择正确的函数版本,但随着程序越来越多以支持越来越多的硬件变体,这变得不切实际.我不得不在整个地方添加案例陈述.

我也尝试过中间函数层来确定使用哪个函数,但它们没有多大帮助.每当我们添加新变体时,我仍然需要在多个位置更新case语句.使用函数指针,我只需要更改初始化函数.