【问题标题】:C++ static rather than dynamic polymorphismC++ 静态而不是动态多态
【发布时间】:2013-10-07 05:24:30
【问题描述】:

我正在尝试构建一个通用算法。到目前为止,我已经使用类层次结构和指针实现了这一点,如下例所示:

struct Base{
    virtual double fn(double x){return 0;}
};

class Derived : public  Base{
    double A;
public:
    Derived(double a) : A(a) {}
    double fn(double x) { return A*x;}
};

//Some other implementations

class algo{
    double T;
    std::unique_ptr<Base> b_ptr;
public:
    algo(double t, std::unique_ptr<Base>& _ptr); //move constructor...
    //Some constructors
    double method(double x){ return T*b_ptr->fn(x);}

};

然后按如下方式实现此设置:

int main(){
    std::unique_ptr<Derived> ptr(new Derived(5.4));
    algo(3.2,ptr);
    method(2.4);

    return 0;
}

当然,这是一个非常简单的示例,但它可以解决我的问题。据我了解,以这种方式使用派生类意味着该方法是在运行时而不是在编译时选择的。由于我的算法不需要任何动态行为——一切都是在编译时确定的——这是不必要的效率损失。有没有办法在编译时执行上述操作,即静态多态性?

据我了解,只能使用模板获得静态多态性。但是,我无法找到具有非原始类型的实现模板。与上面的示例一样,我需要具有非默认构造函数的派生类,这似乎是不可能的......有人可以提供任何解决方案来解决这个问题吗?

【问题讨论】:

  • 您对不必要的动态行为的观察是精明的:如果您必须推迟决定您需要运行时的实际类型,您应该只有多态类层次结构。很好的例子是解析来自网络协议的消息或在事件循环中处理事件。否则,如果你真的知道你需要什么类型,那么虚函数多态不是正确的工具。
  • it's only possible to get static polymorphism using templates 多态是基于当前对象类型调用正确的函数。所以我想说函数重载也是静态多态。

标签: c++ templates static-polymorphism


【解决方案1】:

您的 Base 类和 Derived 似乎代表一个只有一个成员函数的函数, 所以我们很可能完全消除多态性并将一个函数传递给算法:

#include <iostream>
#include <utility>

template <class Function>
class algo
{
    double t;
    Function fn;

public:
    algo(double t, const Function& fn)
        : t{t}, fn{fn}
    { }
    double method(double x){ return t * fn(x);}

};

template <class Function>
algo<Function> make_algo(double t, Function&& fn)
{
    return algo<Function>(t, std::forward<Function>(fn));
}

int main()
{
    const double someValue = 123;
    const double anotherValue = 987;

    auto algo = make_algo(anotherValue, [someValue](double otherValue) {
        return someValue * otherValue;
    });

    std::cout << std::fixed << algo.method(321) << std::endl;
}

【讨论】:

  • 您可以进一步概括它,并将算法上的双精度也设为模板参数。
  • 这是一个非常有趣的回复,非常感谢!一个函数类的例子是一个简单的例子。通常,派生类有多个函数,而且函数可能相当复杂。函数传递的方法太难以理解了!可以提前定义函数然后传递它们吗?我刚刚发现了std::function wrapper,这和上面的方法类似还是使用了动态多态?
  • 使用 std::function 而不是将函数作为模板传递可能会导致代码变慢。您的另一种选择是使用策略类,这可能是您希望静态绑定算法方法的路径。
  • 函数支持模板参数的类型推导,类不支持,因此您创建一个工厂函数以使构造algo 的语法更清晰。 IE。 auto a = make_algo(3.2, NotDerivedAnymore{123.2});algo&lt;NotDerivedAnymore&gt; a{2.3, NotDerivedAnymore{123.2})。这在答案中的函数示例中更加明显。您必须将 lambda 存储在一个变量中,然后使用 decltype 来获取它的类型。
  • 不一定,只要不使用虚函数,就不会再使用动态调度了。
猜你喜欢
  • 2012-03-15
  • 1970-01-01
  • 2019-06-28
  • 2014-06-30
  • 1970-01-01
  • 2013-05-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多