繁体   English   中英

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

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

我正处于一个班级,我们称之为Generic 这个类有成员和属性,我打算在std::vector<Generic>或类似的地方使用它,处理这个类的几个实例。

此外,我想专门化这个类,泛型和专用对象之间的唯一区别是私有方法,它不访问类的任何成员(但由其他方法调用)。 我的第一个想法是简单地将其声明为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; }
}

因此我想我必须使用std::vector<Generic*> ,并动态创建和销毁对象。

一位朋友建议我为我的Generic类使用std::function<>属性,并将specialFunc作为参数提供给构造函数,但我不知道如何正确地执行它。

这两种方法的优点和缺点是什么,还有其他(更好的)方法来做同样的事情吗? 我很好奇。

有关详细信息,我实例化的每个对象的特化将在运行时确定,具体取决于用户输入。 我可能最终会得到很多这些对象(还不确定有多少),所以我想避免任何不必要的开销。

virtual函数和重载模型是一种关系,而std::function模拟一个has-a关系。

使用哪一个取决于您的具体用例。

使用std::function可能更灵活,因为您可以在不引入新类型的情况下轻松修改功能。


性能不应该是这里的主要决策点,除非这个代码可以证明(即你测量过)程序中的紧密循环瓶颈。

首先,让我们把性能抛到窗外。

如果你使用virtual函数,正如你所说,你可能会得到很多具有相同接口的类:

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

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

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

使用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) {}
};

实际上,如果这是你正在使用类的唯一的东西,你也可以删除它,并在调用者级别使用std::function<void(float)>

std::function优点:

1)更少的代码(N个函数有1个类,而虚函数需要N个函数的N个类。我假设这个函数是类之间唯一不同的东西)。
2)更灵活(如果你愿意,你可以通过捕获保持状态的lambda)。
3)如果您将类作为模板编写,则可以根据需要将其用于各种函数签名。

使用std::function解决了你试图用virtual std::function解决的任何问题,它似乎做得更好。 但是,我不打算断言std::function 总是比几个类中的一堆虚函数更好。 有时,这些功能必须是私有的和虚拟的,因为它们的实现与任何外部调用者无关,因此灵活性不是优势。

std::function缺点:

1)我正要写出来,你不能访问的私有成员generic类,但后来我意识到,你可以修改std::function的类本身与持有捕捉拉姆达this 根据你概述课程的方式,这应该不是问题,因为它似乎无视任何类型的内部状态。

这两种方法的优点和缺点是什么,还有其他(更好的)方法来做同样的事情吗?

我能看到的问题是“你希望如何定义你的课程?” (如,什么是公共界面?)

考虑创建一个这样的API:

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

现在,您可以无需关心地创建任何Generic实例。 如果你不知道你将在specialFunc放置什么,这是最好的选择(“你不知道”意味着你的代码的客户可能在一个月内决定从那里的另一个库中放置一个函数,一个相同的函数(“接收”) x,返回x“),访问某个数据库获取值,将有状态仿函数传递给函数或其他任何东西)。

此外,如果specialFunc可以为现有实例更改(即使用specialFunc创建实例,使用它,更改specialFunc ,再次使用它等),您应该使用此变体。

此变体可能会被其他约束强加给您的代码库。 (例如,如果想避免使Generic虚拟化,或者由于其他原因需要它是final的)。

如果(另一方面)你的specialFunc只能从有限数量的实现中选择,并且客户端代码以后无法决定他们想要别的东西 - 即你只有相同的功能和价值加倍 - 就像在你的例子中 - 然后你应该依赖于专业化,比如问题中的代码。

TLDR :根据班级的使用情况决定。

编辑 :关于beter(或至少是替代)的方法...你可以在“按需”的基础上在你的类中注入specialFunc:

也就是说,而不是这个:

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

你可以这样写:

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

这为您提供了更多的灵活性(您可以使用单个实例使用不同的特殊功能),代价是更复杂的客户端代码。 这也可能是您不想要的灵活性(太多)。

暂无
暂无

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

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