Re: on a design question using C++
On Feb 7, 10:42 am, "nvinh...@gmail.com" <nvinh...@gmail.com> wrote:
Thanks to all your support, I managed to write that code. Here
it is:
#include <iostream>
#include <math.h>
#include <boost/shared_ptr.hpp>
using namespace std;
using boost::shared_ptr;
class LinearSoftening
{
public:
LinearSoftening
( double ki, double kc )
: ki_(ki), kc_(kc) {}
double evalFunc ( double x ) { return ki_ + kc_ * x;}
double evalDeri ( double x ) { return kc_;}
private:
double ki_;
double kc_;
};
class ExponentialSoftening
{
public:
ExponentialSoftening
( double ki, double alpha, double beta )
: ki_(ki), alpha_(alpha), beta_(beta){}
double evalFunc ( double x )
{
return ki_ + exp( 1. - alpha_ + beta_ * x );
}
double evalDeri ( double x ) { return alpha_ + beta_;}
private:
double ki_;
double alpha_;
double beta_;
};
class SofteningLawInterface
{
public:
virtual double evalFunc ( double x ) = 0;
virtual double evalDeri ( double x ) = 0;
};
template < class SofteningLawPolicy>
class SofteningLaw : public SofteningLawInterface
{
public:
SofteningLaw
( const SofteningLawPolicy& policy ) : policy_(policy)
{};
double evalFunc ( double x ){ return policy_.evalFunc(x);}
double evalDeri ( double x ){ return policy_.evalDeri(x);}
private:
SofteningLawPolicy policy_;
};
Just a note: in this case, the use of a Policy is just an
unnecessary complication. You should just derive the softening
laws directly from the SofteningLawPolicy, and forget about the
templates.
class Application
{
public:
double computeDamage ( double kappa )
{
return softLaw_->evalFunc ( kappa );
}
double computeDeriOfDamage ( double kappa )
{
return softLaw_->evalDeri ( kappa );
}
template <class SoftLawPolicy>
void setSofteningLaw ( const SoftLawPolicy& policy )
{
softLaw_.reset ( new SofteningLaw<SoftLawPolicy>(policy) );
}
private:
shared_ptr<SofteningLawInterface> softLaw_;
};
int main ()
{
// compile time
typedef SofteningLaw<LinearSoftening> LinearSoftLaw;
typedef SofteningLaw<ExponentialSoftening> ExponeSoftLaw;
LinearSoftening linearSoft(10., 50.);
ExponentialSoftening exponeSoft(10., 0.99, 100.);
LinearSoftLaw linear(linearSoft);
ExponeSoftLaw expone(exponeSoft);
// run time
Application app;
app.setSofteningLaw( linear );
And this doesn't cause a core dump at the end of execution?
You should replace shared_ptr with a raw pointer in Application.
(I suspected as much when I saw the shared_ptr. Shared_ptr is
almost never a good solution for externally implemented
strategies.)
// compare performance
const int n = 1000000000;
for ( int i = 0; i < n; i++ )
{
//double fval1 = linear.evalFunc(0.1);
//double fder1 = linear.evalDeri(0.1);
//cout << " fval1: " << fval1 << ", fderi1: " << fder1 << "\n";
double fval2 = app.computeDamage (0.1);
double fder2 = app.computeDeriOfDamage (0.1);
//cout << " fval2: " << fval2 << ", fderi2: " << fder2 << "\n";
}
return 0;
}
I did a performance comparison between object defined at
compile time and at run time, the result is that the latter is
slower than the former:
Obviously. In one case, the compiler has done the type
resolution; in the other, you do it each time you call the
function.
The template method pattern might be slightly faster (because it
only involves one object, not two), but it still requires a
virtual function call. If performance is an issue, you probably
need to use the template variant of the template method pattern.
real 0m43.238s
user 0m43.127s
sys 0m0.088s
real 1m28.149s
user 1m27.965s
sys 0m0.152s
Since I am calling this code in a tight loop, I think that I
have to fall back to the first approach. But I then lose the
beauty and clarity of template code.
Just the opposite. You need templates, rather than virtual
functions: make Application a template over the Policy class.
That way, the calls to the policy won't be virtual; you can even
inline the functions in the policy for more speed.
--
James Kanze (GABI Software) email:james.ka...@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34