简体   繁体   English

虚拟重载vs`std :: function`成员?

[英]virtual overloading vs `std::function` member?

I'm in a situation where I have a class, let's call it Generic . 我正处于一个班级,我们称之为Generic This class has members and attributes, and I plan to use it in a std::vector<Generic> or similar, processing several instances of this class. 这个类有成员和属性,我打算在std::vector<Generic>或类似的地方使用它,处理这个类的几个实例。

Also, I want to specialize this class, the only difference between the generic and specialized objects would be a private method, which does not access any member of the class (but is called by other methods). 此外,我想专门化这个类,泛型和专用对象之间的唯一区别是私有方法,它不访问类的任何成员(但由其他方法调用)。 My first idea was to simply declare it virtual and overload it in specialized classes like this: 我的第一个想法是简单地将其声明为virtual并在专门的类中重载它,如下所示:

class Generic
{
    // all other members and attributes
    private:
        virtual float specialFunc(float x) const =0;
};

class Specialized_one : public Generic
{
    private:
        virtual float specialFunc(float x) const{ return x;}
};

class Specialized_two : public Generic
{
    private:
        virtual float specialFunc(float x) const{ return 2*x; }
}

And thus I guess I would have to use a std::vector<Generic*> , and create and destroy the objects dynamically. 因此我想我必须使用std::vector<Generic*> ,并动态创建和销毁对象。

A friend suggested me using a std::function<> attribute for my Generic class, and give the specialFunc as an argument to the constructor but I am not sure how to do it properly. 一位朋友建议我为我的Generic类使用std::function<>属性,并将specialFunc作为参数提供给构造函数,但我不知道如何正确地执行它。

What would be the advantages and drawbacks of these two approaches, and are there other (better ?) ways to do the same thing ? 这两种方法的优点和缺点是什么,还有其他(更好的)方法来做同样的事情吗? I'm quite curious about it. 我很好奇。

For the details, the specialization of each object I instantiate would be determined at runtime, depending on user input. 有关详细信息,我实例化的每个对象的特化将在运行时确定,具体取决于用户输入。 And I might end up with a lot of these objects (not yet sure how many), so I would like to avoid any unnecessary overhead. 我可能最终会得到很多这些对象(还不确定有多少),所以我想避免任何不必要的开销。

virtual functions and overloading model an is-a relationship while std::function models a has-a relationship. virtual函数和重载模型是一种关系,而std::function模拟一个has-a关系。

Which one to use depends on your specific use case. 使用哪一个取决于您的具体用例。

Using std::function is perhaps more flexible as you can easily modify the functionality without introducing new types. 使用std::function可能更灵活,因为您可以在不引入新类型的情况下轻松修改功能。


Performance should not be the main decision point here unless this code is provably (ie you measured it) the tight loop bottleneck in your program. 性能不应该是这里的主要决策点,除非这个代码可以证明(即你测量过)程序中的紧密循环瓶颈。

First of all, let's throw performance out the window. 首先,让我们把性能抛到窗外。

If you use virtual functions, as you stated, you may end up with a lot of classes with the same interface: 如果你使用virtual函数,正如你所说,你可能会得到很多具有相同接口的类:

class generic {
    virtual f(float x);
};

class spec1 : public generic {
    virtual f(float x);
};

class spec2 : public generic {
    virtual f(float x);
};

Using std::function<void(float)> as a member would allow you to avoid all the specializations: 使用std::function<void(float)>作为成员将允许您避免所有特化:

class meaningful_class_name {
    std::function<void(float)> f;

public:
    meaningful_class_name(std::function<void(float)> const& p_f) : f(p_f) {}
};

In fact, if this is the ONLY thing you're using the class for, you might as well just remove it, and use a std::function<void(float)> at the level of the caller. 实际上,如果这是你正在使用类的唯一的东西,你也可以删除它,并在调用者级别使用std::function<void(float)>

Advantages of std::function : std::function优点:

1) Less code (1 class for N functions, whereas the virtual method requires N classes for N functions. I'm making the assumption that this function is the only thing that's going to differ between classes). 1)更少的代码(N个函数有1个类,而虚函数需要N个函数的N个类。我假设这个函数是类之间唯一不同的东西)。
2) Much more flexibility (You can pass in capturing lambdas that hold state if you want to). 2)更灵活(如果你愿意,你可以通过捕获保持状态的lambda)。
3) If you write the class as a template, you could use it for all kinds of function signatures if needed. 3)如果您将类作为模板编写,则可以根据需要将其用于各种函数签名。

Using std::function solves whatever problem you're attempting to tackle with virtual functions, and it seems to do it better. 使用std::function解决了你试图用virtual std::function解决的任何问题,它似乎做得更好。 However, I'm not going to assert that std::function will always be better than a bunch of virtual functions in several classes. 但是,我不打算断言std::function 总是比几个类中的一堆虚函数更好。 Sometimes, these functions have to be private and virtual because their implementation has nothing to do with any outside callers, so flexibility is NOT an advantage. 有时,这些功能必须是私有的和虚拟的,因为它们的实现与任何外部调用者无关,因此灵活性不是优势。

Disadvantages of std::function : std::function缺点:

1) I was about to write that you can't access the private members of the generic class, but then I realized that you can modify the std::function in the class itself with a capturing lambda that holds this . 1)我正要写出来,你不能访问的私有成员generic类,但后来我意识到,你可以修改std::function的类本身与持有捕捉拉姆达this Given the way you outlined the class however, this shouldn't be a problem since it seems to be oblivious to any sort of internal state. 根据你概述课程的方式,这应该不是问题,因为它似乎无视任何类型的内部状态。

What would be the advantages and drawbacks of these two approaches, and are there other (better ?) ways to do the same thing ? 这两种方法的优点和缺点是什么,还有其他(更好的)方法来做同样的事情吗?

The issue I can see is "how do you want your class defined?" 我能看到的问题是“你希望如何定义你的课程?” (as in, what is the public interface?) (如,什么是公共界面?)

Consider creating an API like this: 考虑创建一个这样的API:

class Generic
{
    // all other members and attributes
    explicit Generic(std::function<float(float)> specialFunc);
};

Now, you can create any instance of Generic , without care. 现在,您可以无需关心地创建任何Generic实例。 If you have no idea what you will place in specialFunc , this is the best alternative ("you have no idea" means that clients of your code may decide in one month to place a function from another library there, an identical function ("receive x, return x"), accessing some database for the value, passing a stateful functor into your function, or whatever else). 如果你不知道你将在specialFunc放置什么,这是最好的选择(“你不知道”意味着你的代码的客户可能在一个月内决定从那里的另一个库中放置一个函数,一个相同的函数(“接收”) x,返回x“),访问某个数据库获取值,将有状态仿函数传递给函数或其他任何东西)。

Also, if the specialFunc can change for an existing instance (ie create instance with specialFunc , use it, change specialFunc , use it again, etc) you should use this variant. 此外,如果specialFunc可以为现有实例更改(即使用specialFunc创建实例,使用它,更改specialFunc ,再次使用它等),您应该使用此变体。

This variant may be imposed on your code base by other constraints. 此变体可能会被其他约束强加给您的代码库。 (for example, if want to avoid making Generic virtual, or if you need it to be final for other reasons). (例如,如果想避免使Generic虚拟化,或者由于其他原因需要它是final的)。

If (on the other hand) your specialFunc can only be a choice from a limited number of implementations, and client code cannot decide later they want something else - ie you only have identical function and doubling the value - like in your example - then you should rely on specializations, like in the code in your question. 如果(另一方面)你的specialFunc只能从有限数量的实现中选择,并且客户端代码以后无法决定他们想要别的东西 - 即你只有相同的功能和价值加倍 - 就像在你的例子中 - 然后你应该依赖于专业化,比如问题中的代码。

TLDR : Decide based on the usage scenarios of your class. TLDR :根据班级的使用情况决定。

Edit : regarding beter (or at least alternative) ways to do this ... You could inject the specialFunc in your class on an "per needed" basis: 编辑 :关于beter(或至少是替代)的方法...你可以在“按需”的基础上在你的类中注入specialFunc:

That is, instead of this: 也就是说,而不是这个:

class Generic
{
public:
    Generic(std::function<float(float> f) : specialFunc{f} {}

    void fancy_computation2() { 2 * specialFunc(2.); }
    void fancy_computation4() { 4 * specialFunc(4.); }
private:
    std::function<float(float> specialFunc;
};

You could write this: 你可以这样写:

class Generic
{
public:
    Generic() {}

    void fancy_computation2(std::function<float(float> f) { 2 * f(2.); }
    void fancy_computation4(std::function<float(float> f) { 4 * f(4.); }
private:
};

This offers you more flexibility (you can use different special functions with single instance), at the cost of more complicated client code. 这为您提供了更多的灵活性(您可以使用单个实例使用不同的特殊功能),代价是更复杂的客户端代码。 This may also be a level of flexibility that you do not want (too much). 这也可能是您不想要的灵活性(太多)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM