在某些情况下std::function
可以代替继承。 下面的两段代码是非常相似的(大约在同一成本调用函数时,几乎签名和在大多数情况下相同的使用标准::功能并不需要我们做的额外副本A
也):
struct Function
{
virtual int operator()( int ) const =0;
};
struct A
: public Function
{
int operator()( int x ) const override { return x; }
};
使用std::function
,我们可以重写此为
using Function = std::function<int (int)>;
struct A
{
int operator()( int x ) const { return x; }
};
为了使更清晰,这两个片段是如何关联的:他们都可以通过以下方式使用:
int anotherFunction( Function const& f, int x ) { return f( x ) + f( x ); }
int main( int argc, char **argv )
{
A f;
anotherFunction( f, 5 );
return 0;
}
后一种方法更灵活,因为我们没有从一些共同的基类派生我们的类。 之间的唯一关系Function
式的对象是基于他们的能力。 在面向对象的程序设计方面,它可能会被认为是不干净的(但不是在函数式编程当然方面)。
除此之外,还有两种解决方案之间的任何其他方面的差异? 是否有任何的一般准则时要使用该解决方案,或仅是个人喜好的问题? 是否有其中一个解决方案出来,执行其他任何情况下?
小幅回调第一:请注意,这个:
int anotherFunction( Function f, int x ) { return f( x ) + f( x ); }
不会与基于继承的解决方案编译,因为Function
正在采取按价值计算,它是抽象的。 如果不是抽象的,而另一方面,你会得到切片 ,这是不是你想要的。
相反,你必须把你的Function
引用(可能通过引用派生对象const
),以便采取多态性的优势:
int anotherFunction( Function const& f, int x ) { return f( x ) + f( x ); }
这是不是很实用类,所以如果你是热衷于函数式编程(如你似乎是),你可能希望避免的,只是因为这个它。
这就是说,这里是我提供指导:
如果可以,使用模板 :
template<typename F> int anotherFunction(F f, int x) { return f(x) + f(x); }
一般来说,当它可以在所有被使用,静态(编译时,基于模板的)多态性优选考虑动态(运行时,继承系)多态性,因为:
卓越的灵活性 :你不必改变你的类型的定义,使他们从一个共同的基类派生以便对它们进行一般使用。 这允许您,例如,写:
anotherFunction([] (int x) { return x * 2; }, 42);
以及:
anotherFunction(myFxn, 42); // myFxn is a regular function
甚至:
anotherFunction(my_functor(), 42); // my_functor is a class
卓越的性能 :因为你没有通过一个虚拟的表来调用和编译器知道函数调用将如何解决,它可以内联呼吁给予你更高的性能(如果它认为这是合理的)。
如果你不能使用模板 ,因为要调用的函数将在运行时间待定, 使用std::function
:
int anotherFunction(std::function<int (int)> f, int x) { return f(x) + f(x); }
这也给你足够的灵活性,以传递lambda表达式,函数指针,仿函数,基本上任何可调用的对象。 见,例如, 这个Q&A在计算器上 。
使用std::function
可能会带来显著运行时开销相对于基于模板的设计,或许也是对于像一个你勾勒出一个硬编码基于继承的解决方案轻微的未成年人的开销,但它给你的灵活性和它是一个标准的成语。 此外,由于总是在性能是一个问题,进行测量备份任何假设 - 你可能会得到意想不到的结果。
您通常需要求助于这类std::function
为基础的设计,当你想存储任何类型供以后调用的可调用的对象,如在的情况下, 命令设计模式 ,或者当你调用对象的异质集合待处理和一般调用。 有关何时使用一个讨论std::function
,而不是模板,看到这个Q&A在计算器上 。
所以,你应该什么时候再打一个硬编码的设计中使用继承 ? 那么,在所有这些地方1和2是不可行的情况下 - 老实说,我不认为现在的任何权利,但我敢肯定有人能拿出一个角落的情况。 请注意,是C ++ 11 没有必要为了让使用的std::function
式的成语,因为升压拥有boost::function
和boost::bind
实现,预售日期(并担任灵感对)C ++ 11的std::function
和std::bind
。
TL; DR:使用模板或std::function
。