C++ 中的可调用对象与其他编程语言中的函数对象有何异同?

【字号: 日期:2023-04-17浏览:24作者:雯心

问题描述

C++ 中的可调用对象与其他编程语言中的函数对象有何异同?

问题解答

回答1:

题目问的其它语言,这个太广泛了,因为编程语言这么多,有形如C语言这种传统的函数,也有形如java那样无法独立存在的函数,还有各类脚本语言的不同形式的函数。

不过在函数是第一等公民的语言里,要求函数能做到

函数可以独立存在,且可在任意地方执行

函数的作用域是词法作用域,且可捕获外部变量

函数可从另外一个函数返回,也可以作为别的函数的参数(高阶函数)

函数从别的函数生成后,所引用的作用域依旧可访问,而不是被销毁

在不少脚本语言和新兴语言里,函数大都是有以上特性表现的。

关于不同语言闭包捕获的问题,可以参考一下我之前写过的一篇文章 https://zhuanlan.zhihu.com/p/...

再说C++,C++有四个可以用来调用的东西

函数

函数指针

重载了()运算符的类

lambda

这四个东西的类型各不相同,但是都可以做到执行函数,使用上都是形如func()。

函数和函数指针在一定情况下是可以互转的,它在C语言里就存在,但是它存在一些难以解决的问题,包括

函数类型难写,难读

函数内部无法保存状态,没有办法实现外层变量捕获

重载了()运算符的类是C++提供的一个仿函数写法,它可以实现不少做法

class Test{public: Test(int a):_a(a){} int operator ()(int b){ return _a+b; } private: int _a;};

在使用上只要这样:

Test sum1 = Test(1);std::cout << sum1(10) << ’n’;Test sum2 = Test(10);std::cout << sum2(10) << ’n’;

可以看到sum1和sum2的内部都保存了一个状态,进而表现不一,这是普通的函数和函数指针无法做到的。

然而重载了()运算符的类的一大缺点就是不够轻量,不管是占用空间还是执行效率上和函数/函数指针都存在差距。

C++11引入了lambda,典型的lambda是这样

int a = 10;auto func = [&a](int b){return a+b;};std::cout << func(10) << ’n’;a = 20;std::cout << func(10) << ’n’;

可以看到lambda可以轻松捕获变量,实现闭包效果,所以我们在很多场合下可以使用lambda来代替重载了()运算符的类。

不过lambda也有局限,首先是它的类型是无法手动写出来的,也就是说对于同样的两个lambda,它的类型是不同的

auto func = [&a](int b){return a+b;};auto func2 = [&a](int b){return a+b;};std::cout << (typeid(func).name() != typeid(func2).name()) << ’n’;

所以我们只能定义的时候只能用auto,而且如果我们想把lambda存到vector、list等容器里,就必须要用包装类std::function,它本质上是个泛型的模板类,也同样重载了()操作符

std::function<int(int)> func3 = func;

使用std::function之后,lambda的轻量优势就消失了,不过有的时候也不得不这么做。

相关文章: