什么时候使用std :: function而不是继承? [英] When to use std::function instead of inheritance?

查看:281
本文介绍了什么时候使用std :: function而不是继承?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在某些情况下, std :: function 可以替换继承。以下两个代码片段非常相似(在调用函数时大致相同的成本,在签名中使用几乎相同,并且在大多数情况下,std :: function不需要我们额外复制 A 以及):

In some cases std::function can replace inheritance. The following two code snippets are very similar (about the same costs when calling the function, almost the same usage in signatures and in most cases std::function does not require us to make an extra copy of A as well):

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; }
};

为了更清楚,两个片段之间的关系如下:以下方式:

In order to make more clear, how the two snippets are related: both of them can be used in the following way:

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 -like对象之间的唯一关系是基于它们的能力。在面向对象的编程方面,它可能被认为不太干净(当然不是在函数式编程方面)。

The latter approach is more flexible, because we do not have to derive our classes from some common base class. The only relationship between Function-like objects is based on their capabilities. In terms of object-orientated programming it might be considered less clean (but not in terms of functional programming, of course).

除此之外,是否有其他差异之间的两个解决方案?在使用哪种解决方案或只是个人偏好的问题时,是否有任何一般性指南?

Apart from that, are there any other differences between the two solutions? Are there any general guidelines when to use which of the solutions or is it only a matter of personal preference? Are there any cases where one solution out-performs the other?

推荐答案

首先进行小修正:注意,这是:

A small correction first: notice, that this:

int anotherFunction( Function f, int x ) { return f( x ) + f( x ); }

无法使用基于继承的解法编译,因为 Function 是按值取的,它是抽象的。如果它不是抽象的,另一方面,你会得到切片,这不是你想要的。

Would not compile with the inheritance-based solution, since Function is being taken by value and it is abstract. If it were not abstract, on the other hand, you would get slicing, which is not what you want.

相反,你必须通过引用取得你的 Function $ c> const ),以便利用多态性:

Rather, you would have to take your Function-derived object by reference (possibly by reference to const) in order to take advantage of polymorphism:

int anotherFunction( Function const& f, int x ) { return f( x ) + f( x ); }

这不是很像函数式的,所以如果你热衷于函数式编程你似乎是)你可能想要避免它只是因为这个。

And this is not very functional-like, so if you're keen on functional programming (as you seem to be) you may want to avoid it just because of this.

这就是我要提供的指南:

That said, here is the guideline I would provide:


  1. 如果可以,使用模板

template<typename F>
int anotherFunction(F f, int x) { return f(x) + f(x); }

一般来说,当它可以使用时,静态(编译时,基于模板)多态性被认为优于动态(运行时,基于继承)多态性,因为:

In general, when it can be used at all, static (compile-time, template-based) polymorphism is considered preferable to dynamic (run-time, inheritance-based) polymorphism, because of:


  • 灵活性:您不必更改类型的定义,并使它们从公共基类中派生,以便一般使用它们。这允许你写,例如:

  • Superior flexibility: you do not have to change the definition of your types and make them derive from a common base class in order for them to be used generically. This allows you, for instance, to write:

anotherFunction([] (int x) { return x * 2; }, 42);

以及:

anotherFunction(myFxn, 42); // myFxn is a regular function

或者:

anotherFunction(my_functor(), 42); // my_functor is a class


  • 不通过虚拟表调用,编译器知道如何解决函数调用,它可以内联调用以给你更大的性能(如果它认为这是合理的)。

  • Superior performance: since you are not calling through a virtual table and the compiler knows how function calls will be resolved, it can inline the call to give you greater performance (if it deems this to be reasonable).

    如果无法使用模板 使用 std :: function

    If you cannot use templates, because the function to be invoked is going to be determined at run-time, use std::function:

     int anotherFunction(std::function<int (int)> f, int x) 
     { 
         return f(x) + f(x); 
     }
    

    这也可以让你有足够的灵活性传入lambdas,函数指针, ,基本上任何可调用对象。例如,请参阅 在StackOverflow上的此问答

    This will also give you enough flexibility to pass in lambdas, function pointers, functors, basically any callable object. See, for instance, this Q&A on StackOverflow.

    使用 std :: function 可能会对基于模板的设计带来大量的运行时间开销,并且对于基于硬编码的基于继承的解决方案(例如您所概述的解决方案)也可能有微小的开销,但是它给予您灵活性,并且它是一个标准习语。此外,一如既往,当性能是一个问题,做测量来备份任何假设 - 你可能会得到令人惊讶的结果。

    Using std::function may bring a significant run-time overhead with respect to a template-based design, and perhaps also a slight minor overhead with respect to a hardcoded inheritance-based solution like the one you outline, but it gives you flexibility and it is a standard idiom. Moreover, as always when performance is a concern, make measurements to back up any assumption - you might get surprising results.

    你通常需要诉诸这种<当你想存储任何类型的可调用对象以供稍后调用时使用c $ c> std :: function 的设计,例如命令设计模式,或者当您有可异常集合的可调用对象被一般处理和调用时。有关何时使用 std :: function 而不是模板的讨论,请参阅 在StackOverflow上的此问答

    You usually need to resort to this kind of std::function-based design when you want to store callable objects of any type for later invocation, as in the case of the Command design pattern, or when you have a heterogenous collection of callable objects to be treated and invoked generically. For a discussion on when to use std::function instead of templates, see this Q&A on StackOverflow.

    诉诸于使用继承的硬编码设计?好吧,在所有这些情况下,1.和2.不可行 - 老实说,我现在不能想到任何权利,但我相信有人可能想出一个角落的情况。注意,为了使用 std :: function -like idiom,C ++ 11不是必需的,因为Boost有 boost :: function 和一个 boost :: bind 实现(并作为灵感)C + + 11的 std :: function std :: bind

    So when should you resort to a hardcoded design using inheritance? Well, in all those cases where 1. and 2. are not viable - honestly, I can't think of any right now, but I'm sure someone could come up with a corner case. Notice, that C++11 is not necessary in order to make use of an std::function-like idiom, since Boost has a boost::function and a boost::bind implementation that pre-date (and served as an inspiration for) C++11's std::function and std::bind.






    TL; DR :使用模板或 std :: function

    这篇关于什么时候使用std :: function而不是继承?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

  • 查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆