函数指针与匿名函数


title: 函数指针与匿名函数
date: 2024-02-02 22:00:00
categories:

  • C++
  • 函数
    tags: 函数指针与匿名函数 #

函数指针

什么是函数指针?

函数指针是指向函数的指针变量。 因此“函数指针”本身首先应是指针变量,只不过该指针变量指向函数。这正如用指针变量可指向整型变量、字符型、数组一样,这里是指向函数。

函数指针的声明形式如下:

return_type (*pointer_name)(parameter_types);

其中,return_type 是函数返回类型,pointer_name 是指针变量的名称,parameter_types 是函数参数的类型。下面是一个简单的例子:

#include <iostream>

void myFunction(int x) {
    std::cout << "Function called with value: " << x << std::endl;
}

int main() {
    // 声明一个指向函数的指针
    void (*funcPtr)(int);

    // 将函数指针指向特定的函数
    funcPtr = &myFunction;

    // 通过函数指针调用函数
    (*funcPtr)(42);

    return 0;
}

这个例子中,funcPtr 是一个指向接受一个整数参数并返回 void 的函数的指针。然后,它被赋值为指向 myFunction 函数的指针,并通过该指针调用函数

或者我们现在外部定义一个函数HelloWorld,然后用auto类型的变量function来试着推导函数名的类型,发现自动推导得到function类型为void(*)(int a) 就和之前说的一样,这时候我们可以使用function来调用函数(这里例子起名为了funcfunction(8)/func(8); 一般来说这个类型名是不够直观的,可以直接使用auto或typedef来定义其他名字就像line 14 .

void HelloWorld(int a)
{
	std::cout << "Hello World! the value:" <<a <<std::endl;

}
int main()
{

    auto function=HelloWorld;
	
	void(*func)(int a);
	func = HelloWorld;
	
	typedef void(*HelloWorldfunc)(int a) ;
	HelloWorldfunc function=HelloWorld;
	
    function(8);
	func(8);

}

使用

函数指针其实就像一个变量,但它存储的是函数的地址。通过函数指针,我们可以在程序运行时动态地选择调用哪个函数。

想象一下你有两个不同的函数,但你希望在程序运行时决定到底调用哪个函数。这时候就可以用函数指针。让我用一个更简单的例子来解释:

cppCopy code
#include <iostream>

// 定义两个简单的函数
void sayHello() {
    std::cout << "Hello, ";
}

void sayWorld() {
    std::cout << "World!" << std::endl;
}

int main() {
    // 声明一个函数指针,指向不接受参数也不返回任何值的函数
    void (*ptr)();

    // 根据需要,让函数指针指向不同的函数
    ptr = sayHello;
    ptr();  // 调用 sayHello 函数

    ptr = sayWorld;
    ptr();  // 调用 sayWorld 函数

    return 0;
}

这个例子中,ptr 是一个函数指针,它可以指向 sayHellosayWorld 中的任一个函数。通过改变 ptr 的指向,你可以在程序运行时选择调用不同的函数。

函数指针通常用于实现一些高级的功能,比如回调函数、事件处理等。在大型项目中,函数指针也有助于实现灵活的代码结构。

还可以这样做,在之前的例子中再定义一个foreach函数,在函数里的for循环中通过一个函数来对传入的values操作,这个函数也可以由外部传入,是的,把函数当作一个参数传入另一个函数,(函数在最终的代码中也是存放在某个位置,所以可以传入它的指针),那么就在这个foreach的参数列表中定义一个void(*func)(int)来接受函数的指针

void foreach(const std::vector<int>&values,void(*func)(int))
{
	for (int value : values)
		func(value);
}

这样我们就可以在main中foreach(values,PrintValue); 意味着将values传入foreach中并对每个values进行进行PrintValue操作

对于一个简单的操作再定义一个函数是比较麻烦的,所以有匿名函数( lambda 函数)便于随用随定义,不用到其他地方去定义个函数 ↓ ↓ ↓

lambda

什么是lambda

Lambda表达式是C++11引入的一个特性,它允许你在代码中定义匿名函数,通常用于需要传递函数作为参数的地方。Lambda表达式的语法相对简洁,特别适用于一些短小的函数功能。

Lambda expressions (since C++11) - cppreference.com

Lambda表达式的基本形式如下:

[capture](parameter_list) -> return_type {
    // 函数体
}

其中:

  • capture:用于捕获外部变量,可以省略,或者使用=表示按值捕获,或者&表示按引用捕获。
  • parameter_list:函数参数列表,与普通函数类似,可以为空。
  • return_type:返回类型,可以省略,编译器可以自动推断。
  • 函数体:包含了实际的函数逻辑。

下面是一个简单的例子,演示了Lambda表达式的用法:

#include <iostream>

int main() {
    // Lambda表达式示例:求两个数的和
    auto add = [](int a, int b) -> int {
        return a + b;
    };

    // 使用Lambda表达式
    int result = add(3, 4);
    std::cout << "Sum: " << result << std::endl;

    return 0;
}

在这个例子中,add 是一个Lambda表达式,它接受两个整数参数并返回它们的和。通过auto关键字,编译器会自动推断add的类型。

Lambda表达式通常用于STL算法、函数对象、回调函数等场景,以提供更为简洁的语法。

除了基本形式,Lambda表达式还支持一些高级特性,比如捕获列表的详细控制、变参函数等。

接着函数指针那里的例子,我们不必要去定义PrintValue函数而是直接

foreach(values,[](int value) {std::cout << value << " "; });

或者是写成

auto lambda = [=](int value) {std::cout << value << " "; };
	foreach(values, lambda);

这里传入的参数是lambda,所以不能使用原来的原始函数指针,而是使用中的function来定义参数,因为如果lambda不捕获外部变量的话是可以隐式转换为函数指针形式的,但是如果捕获外部变量的话,对应的函数指针并没有处理该变量的能力,所以不能接收。

函数指针不能接收捕获外部变量的lambda表达式,原因在于lambda表达式和函数指针的本质区别。函数指针是指向函数的指针,它只能指向没有捕获任何外部变量的普通函数或没有捕获外部变量的lambda表达式。这是因为函数指针仅仅存储了函数的地址,而不包含任何上下文信息。

当lambda表达式捕获了外部变量时,它实际上是一个包含了捕获列表的闭包对象。这个闭包对象不仅包含了函数体,还包含了捕获的变量的副本或引用。因此,它的类型不再是一个简单的函数指针,而是一个类的实例,这个类有一个重载的operator()方法。

由于捕获的外部变量是闭包对象的一部分,这使得闭包对象的类型和函数指针的类型不兼容,因此不能将捕获外部变量的lambda表达式赋值给函数指针。如果需要以类似函数指针的方式使用lambda表达式,可以考虑使用std::function,它是一个模板类,能够存储和调用任何可调用对象,包括函数指针、成员函数指针、以及捕获外部变量的lambda表达式。

void foreach(const std::vector<int>&values,std::function<void(int)> func){//...}

std::function 提供了一种将不同类型的可调用对象包装成一个统一接口的方式,使得它们可以以相同的方式被调用

这个lambda实际上是我们构造的一个稍后会用到的函数,如果我们想要传入一个外部变量,也就是例子中定义的这个lambda中,我们想打印的是一个int a =7;的这个外部变量a,就会报错 封闭函数(enclosing function)局部变量不能在 lambda 体中引用,除非其位于捕获列表中 。所以就要再[]这里捕获列表中加入a,= 或者 & ,也可以直接将a写入。

还有一个使用匿名函数的地方是使用find_if时,

  • 26
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
匿名函数指针是指没有具体名称的函数指针。在C语言中,我们可以使用函数指针来存储和传递函数的地址。而匿名函数指针则是没有被命名的函数指针。 通常情况下,我们需要先定义一个函数,然后再通过函数名来获取函数的地址,进而赋值给函数指针变量。但是有些情况下,我们可能只需要临时地定义一个函数,并且不需要给它一个具体的名称,这时就可以使用匿名函数指针。 在C语言中,可以使用函数指针类型来声明匿名函数指针,然后通过函数指针类型定义一个匿名函数,并将其赋值给匿名函数指针变量。例如: ```c int (*anonymous_function_ptr)(int); // 声明匿名函数指针类型 anonymous_function_ptr = ^(int num) { return num * 2; // 定义匿名函数并赋值给匿名函数指针变量 }; int result = anonymous_function_ptr(5); // 调用匿名函数指针所指向的匿名函数 ``` 在上述例子中,首先声明了一个匿名函数指针类型 `int (*)(int)`,然后定义了一个匿名函数并将其赋值给 `anonymous_function_ptr`。最后通过 `anonymous_function_ptr(5)` 调用了该匿名函数,并将结果赋值给 `result`。 需要注意的是,匿名函数指针在C语言中并不是原生支持的特性,上述例子中使用的是一种类似于匿名函数指针的实现方式。在实际开发中,若需要使用匿名函数指针,可以根据具体需求自行实现或使用相关的第三方库。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值