我想在C ++中实现真正的函数。特别是我想评估,区分,添加,乘以这些对象。这是我的实现
class RealFunc {
public:
virtual int Eval(const double& x, double& result) = 0;
virtual int Diff(const double& x, double& result) = 0;
};
class Sqrt : public RealFunc {
public:
int Eval(const double& x, double& result);
int Diff(const double& x, double& result);
};
int Sqrt::Eval(const double& x, double& result) {
if(x<0) return 0;
else {
result = sqrt(x);
return 1;
}
};
int Sqrt::Diff(const double& x, double& result) {
if(x<=0) return 0;
else {
result = 0.5/sqrt(x);
return 1;
}
};
当我尝试添加RealFunc
个对象时,它变得棘手。我必须创建一个继承自RealFunc
RealFunc operator+(const RealFunc& f, const RealFunc& g) {
Sum_RealFunc h(f,g);
return h;
};
class Sum_RealFunc : public RealFunc {
public:
Sum_RealFunc(const RealFunc& f_, const RealFunc& g_) : f(f_), g(g_) {};
int Eval(const double& x, double& result);
int Diff(const double& x, double& result);
private:
RealFunc f;
RealFunc g;
};
int Sum_RealFunc::Eval(const double& x, double& result) {
double temp_f,temp_g;
int success_f,success_g;
success_f = f.Eval(x,temp_f);
success_g = g.Eval(x,temp_g);
result = temp_f+temp_g;
return success_f*success_g;
};
// Same for Sum_RealFunc::Diff
我的问题是我无法使用f
,g
作为Sum_RealFunc
中的成员,因为RealFunc
是抽象的...我应该如何进行干净的实施?
PS:我输入的代码是我正在处理的代码(RxR-> R的函数,具有所有微分方向,如果stepsize成员不为零,则有限差分和其他边函数)
答案 0 :(得分:3)
您面临的问题是,您需要一个适用于值对象(运算符重载)的功能和仅适用于指针(继承/多态)的功能。
作为一个解决方案,你需要一个带有重载运算符的值对象作为通过指针管理的多态对象的包装器:
class RealFuncImpl {
public:
virtual ~RealFuncImpl(); // don't forget this for polymorphic objects
virtual int Eval(const double& x, double& result) = 0;
virtual int Diff(const double& x, double& result) = 0;
};
class RealFunc {
std::shared_ptr<RealFuncImpl> impl;
public:
int Eval(const double& x, double& result);
int Diff(const double& x, double& result);
};
您从Sum_RealFuncImpl
派生RealFuncImpl
并为RealFunc
实施运营商。您可能应该隐藏某些“详细”命名空间中的Impl
类,因为您的代码的最终用户永远不会看到它们。
编辑:
您的Sum_RealFuncImpl
将包含两个std::shared_ptr<RealFuncImpl>
成员。
答案 1 :(得分:1)
由于在构造函数初始值设定项列表中初始化它们,因此可以使成员变量引用。
答案 2 :(得分:1)
您有两种可能性:
通过实现clone
成员,使派生类本身可以通过基类指针进行复制。从派生CRTP类而不是直接从基类派生,这是最方便的。我会把它变成一个本地课程,不要混淆:
struct RealFunc {
virtual std::pair<double,bool> operator() //IMO better than this
(double x)const =0; // reference-argument hackery
virtual std::pair<double,bool> Diff
(double x)const =0;
virtual RealFunc* clone()const =0;
template<class Derived>
struct implementation : RealFunc {
RealFunc* clone() {
return new Derived(*static_cast<const Derived*>(this));
}
};
virtual ~RealFunc(){}
};
现在你只需从implementation
派生你的函数对象,使它们可以克隆:
struct Sqrt : RealFunc::implementation<Sqrt> {
std::pair<double,bool> operator()(double x) {
return x>=0
? std::make_pair(sqrt(x), true)
: std::make_pair(0., false);
}
...
}
现在可以使用std::unique_ptr
很好地完成求和功能:
class Sum_RealFunc : public RealFunc::implementation<Sum_RealFunc> {
std::vector<std::unique_ptr<RealFunc>> summands;
public:
std::pair<double,bool> operator()(double x) {
double result=0;
for(auto& f: summands) {
auto r = (*f)(x);
if(r.second) result += r.first;
else return std::make_pair(0., false);
}
return std::make_pair(result, true);
}
Sum_RealFunc(const Sum_RealFunc& cpy) {
for(auto& f: cpy.summands)
summands.push_back(f->clone());
}
//friend operator+=(RealFunc& acc, const RealFunc& add); //doesn't work
};
不幸的是,这是不足够的间接允许编写简单的和表达式。我在最近解决了所有这些问题的项目中做了一些事情,但是有点复杂:我给每个实例提供了覆盖其行为的选项。像
class RealFunc {
std::unique_ptr<RealFunc> override;
public:
virtual std::pair<double,bool> operator()(double x)const {
return (*override)(x);
}
virtual std::pair<double,bool> Diff(double x)const {
return override->Diff(x);
}
auto implemented() -> RealFunc* {
return implement_override? override->implemented() : this; }
auto implemented()const -> const RealFunc* {
return implement_override? override->implemented() : this; }
virtual RealFunc* clone()const =0;
template<class Derived>
struct implementation : RealFunc {
virtual std::pair<double,bool> operator()(double x)const =0;
virtual std::pair<double,bool> Diff(double x)const =0;
RealFunc* clone() {
return new Derived(*static_cast<const Derived*>(this));
}
};
virtual ~RealFunc(){}
};
不仅如此,您需要使用此方法在所有地方包含大量override
支票。但最终,它可以让你非常顺利地组合功能,比如
RealFunc f = const_realfunc(7.);
for(auto& omega: omegas)
f += sine_angfreq(omega);
RealFunc g = f + noise_func(.3);
...
答案 3 :(得分:1)
尝试
class Sum_RealFunc : public RealFunc {
public:
Sum_RealFunc(RealFunc& f_, RealFunc& g_) : f(f_), g(g_) {};
int Eval(const double& x, double& result);
int Diff(const double& x, double& result);
private:
RealFunc& f;
RealFunc& g;
};
现在f和g是引用而不是很好。