C++中静态多态性而非动态多态性

6

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

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

这是一个非常简单的例子,当然只是为了解答我的问题。据我所知,使用派生类的方式意味着方法在运行时而不是编译时选择。由于我的算法不需要任何动态行为 - 一切都在编译时确定 - 这是无谓的效率损失。是否有一种方法可以在编译时执行上述操作,即静态多态性?
据我所知,只有使用模板才可能获得静态多态性。但我还没有找到如何实现非原始类型的模板。就像上面的例子,我需要具有非默认构造函数的派生类,这似乎是不可能的... 是否有人能提供任何解决方案吗?

你对于不必要的动态行为的观察是敏锐的:只有在必须将需要的实际类型推迟到运行时才应该使用多态类层次结构。好的例子包括从网络协议解析消息或在事件循环中处理事件。否则,如果你确切地知道你需要什么类型,虚函数多态性并不是正确的工具。 - Kerrek SB
只有使用模板才能实现静态多态性。多态性是基于当前对象类型调用正确函数的概念。因此,我想说函数重载也是静态多态性。 - ZijingWu
1个回答

4

您的基类和派生类似乎只表示具有单个成员函数的函数,因此我们完全可以摆脱多态性并将函数传递到algo中:

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

你可以进一步概括它,并将算法中的双精度作为模板参数。 - goji
这是一个非常有趣的回复,非常感谢!单函数类的例子很简单。通常,派生类有多个函数,并且这些函数可能非常复杂。函数传递的方法可能会变得难以阅读!能否预先定义函数,然后再传递它们?我刚刚发现了std::function包装器,它是否类似于上述方法或者使用动态多态性? - Plamen
谢谢!出于兴趣,为什么你使用make_algo(...)函数而不是直接调用构造函数?这样做是为了auto关键字生效吗? - Plamen
1
函数支持模板参数类型推导,而类不支持,因此您需要创建一个工厂函数来使构造“algo”的语法更加清晰。例如:auto a = make_algo(3.2, NotDerivedAnymore{123.2}); 而不是 algo<NotDerivedAnymore> a{2.3, NotDerivedAnymore{123.2})。在答案的函数示例中,这一点更加明显。您需要将lambda存储在变量中,然后使用decltype获取其类型。 - goji
1
不一定,只要你不使用虚函数,就不会再使用动态分派了。 - goji
显示剩余3条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接