自lambdas进入C++以来,“回调”接口是否已过时
Are `Callback` interfaces obsolete since lambdas entered C++?
在我们的代码库中,我们有很多这样的类:
class DirectoryCallback {
public:
virtual ~DirectoryCallback(){};
virtual void process(const std::string &path) = 0;
};
它们通常只有一个目的:包装函数调用。扩展这些接口很无聊。无聊并没有坏处,但我想知道:既然C++中有lambdas和std::function
,这种模式有什么用?因为这正是他们所能做的…包装函数调用。
这个答案有点乱,但需要考虑一些事情。。。。
虚拟函数——用作回调——本质上更具限制性:
-
你知道派生类必须指定一个实现(给定
= 0
),但在派生对象的生存期内它不会变化(在初始化程序列表中设置const std::function
对象也可以做类似的事情,但不必这样), -
您知道回调从构造函数完成到销毁都是活动的
相比之下,掌握指定一组回调lambda的代码的人必须更仔细地研究它们的设置方式和时间,以及它们在对象的生命周期中是否会发生变化。Lambdas可能会从创建它们的函数中捕获更多的输入和上下文,这增加了潜在的复杂性。
设置std::function
回调可能需要更明确的过程代码来设置std::function
变量,除非这是在构造函数的初始化列表中专门完成的。虚拟函数override
更具声明性,这是一些人更喜欢的。
使用虚拟函数的最派生的实现,而在最派生的构造函数中为std::function
指定lambda可能需要通过层次结构将其显式传递给所有级别的基类构造函数。
虚拟函数的const
性质直观地起作用,但通过将std::function
成员设置为lambda来指定行为的派生类有机会获得对派生对象的非const
访问权限,而不管基类设计建议这些回调应该需要什么。
编译器可以很好地理解虚拟调度,并且当对象的动态类型在编译时已知时,通常会通过潜在的内联函数来解析虚拟调度。认为std::function
对象必须实现等效优化是一种延伸,其中lambda名义上是由运行时的派生函数设置的。。。。
虚拟函数被有效地分解为指向每个类表的每个对象指针,这将是使用std::function
s手动编排的更大麻烦。每次回调使用std::function
成员的简单方法内存效率较低。
- "IDispatch::GetTypeInfo()"接口是否正常
- Djinni 记录是否包含可选的接口字段
- 抽象类/接口中的空方法是否被认为是一种好的做法?
- 是否可以从C 调用FORTRAN接口
- C 是否具有接口类概念,如果它在那里,那么它与Java接口类别有何不同
- C++ 接口类继承自具体类是否合理
- 在C 11或更高版本中,是否可以通过Lambda来实现单方法纯Virtual C 接口
- Blas 和 Lapack 库是否有本机 C++(不是 C)接口?
- 是否有任何挂钩接口在编译时间内更换功能
- OmNET++动态检查NED模块是否实现了接口
- 是否在对象中创建临时接口
- 是否有一个更适合键值数据结构的QABSTRACTITEMMODEL类型类/接口
- 我是否必须在C 接口的OPENCV C包装器中自由分配的内存
- 是否可以将C++接口与Objective-C一起使用
- 是否覆盖Direct3D接口
- 自lambdas进入C++以来,“回调”接口是否已过时
- 是否可以检查接口是否在 pcap 中激活
- 导入"RegExp.tlb" C++ COM 接口是否在进程之间隐式共享内存?
- QT检查接口是否真实
- C++库中的文件打开接口是否应该在Windows上使用UTF-8