我正在编写一个数值库,我有一些基于函数及其衍生物的算法。这些必须由用户作为仿函数提供,例如
struct Function{
double operator()(double x, double y){return x*x+y*y);}
};
struct DerivativeX{
double operator()(double x, double y){return 2*x);}
};
//more derivatives...
现在我的算法声明就是:。
template<class F, class F_X, class F_Y>
struct Algorithm
{
Algorithm( F f, F_X fx, F_Y fy):f_(f), fx_(fx), fy_(fy){}
double someFancyComputation( double input) {
//call f_(double,double), fx_(double,double) and fy_(double,double);
private:
F f_;
F_X fx_;
F_Y fy_;
//more other stuff...
};
对于所有使用模板化算法的STL以及关于C ++ 11中模板编程的大惊小怪,我觉得使用模板非常现代和酷。 但是,现在的问题是,为了使用这个算法,用户必须明确地写出所有模板参数:
//construct functors
Algorithm<Function, DerivativeX, DerivativeY> alg( f, fx, fy);
(想象一下有6个衍生品。那要写很多) 其次,它不可能在运行时选择一组函数(衍生物),所以我想在模板上使用继承。
我有两个问题: 首先,您认为在这种情况下使用继承是一个好主意,还是我可以使用其他设计模式?
其次,遗憾的是,我对图书馆继承的使用和陷阱不是很有经验,所以你可以展示或解释一下这种情况是如何做好的吗?
编辑:经过一些研究后我可以提出
struct aBinaryFunction{
double operator()( double x, double y) = 0;
~aBinaryFunction(){}
};
struct Algorithm{
Algorithm( aBinaryFunction* f, aBinaryFunction* fx, aBinaryFunction* fy):f_(f), fx_(fx), fy_(fy){}
double someFancyComputation( double input) {
//call *f_(double,double), *fx_(double,double) and *fy_(double,double);}
private:
aBinaryFunction * f_, fx_, fy_;
//more other stuff...
};
//in main create functors and then call
Algorithm alg(f,fx,fy);
作为可能的实现。现在,所有用户都必须编写从我的库类派生的函数,并且在调用someFancyComputation时要特别注意f fx和fy仍在范围内。这是一种良好做法还是被认为是限制性的?我对这段代码中的原始指针感到非常不舒服,是不是有更好的方法来实现它?
答案 0 :(得分:3)
在C ++中,你有很多工具......
在编译时选择算法时,模板是合适的。
虚拟函数适用于运行时选择。
在RWE
,函数指针,成员函数指针之间还有许多其他可能性。
此外,您可以使用std::function
函数替换构造函数调用(类似于标准库中的make_something
,make_unique
,make_shared
... )。 顺便说一句,我认为构建模板扣除计划用于即将推出的标准。
基本上,如果用户选择要在算法中使用的函数,则必须使用基于运行时多态性的解决方案。如果选择是在编译时进行的,那么选择就是你的选择。基于模板的解决方案可能更快,因为编译器可以优化该特定情况。但是,并非在所有情况下都有用,因为如果在同一程序中使用了许多算法,它也可能会增加代码大小。
假设make_pair
并不简单,并且您希望将算法应用于用户选择或许多编译时类型(如someFancyComputation
)基于继承的解决方案(或上面提到的其他替代方案)如果您的算法只需要使用双精度数,那么请特别优先。
如果某些部分是动态的并且其他部分是静态的(例如可能使用DerivativeX,Y, Z...
),您也可以根据需要混合使用这两种方法。