on a design question using C++

N

nvinhphu

Hello everybody,

I have implemented a code like this, in one of my class who has a
private data member: std::String name_ ..., variables with _ mean
private data members:

void compute ( double x )
{
if ( name_ == "linearSoftening" )
{
fval_ = linearValue ( k1_, k2_, x );
fder_ = linearDerivative ( k1_, k2_, x );
}
else if ( name_ == "exponentialSoftening" )
{
fval_ = linearValue ( k1_, k2_, alpha_, x );
fder_ = linearDerivative ( k1_, k2_, alpha_, x );
}
...
}

So, everytime a new softening law, say powerSoftening, is to be added,
I have to do two things:
(1) Code the two functions powerValue (...) and powerDerivative(...)
(2) Add a else if in the above void compute (double x) method.

I think this design is not object-oriented. I am thinking of the
following design. A base class

class SofteningLaw{
double computeVal ( double x);
double computeDer ( double x);
};

class LinearSofteningLaw : public SofteningLaw
{
private:
double k1_;
double k2_;
public:

double computeVal ( double x){return k1_ + k2_ *x;}
double computeDer ( double x){return k2_;}
};

and other class for each softening law.

Then, in my class, I store a pointer to SofteningLaw as

class myClass{
private:

SofteningLaw* softening_;
double val_;
double der_;

public:

void compute ( double x ){
val_ = softening_-> computeVal (x);
der_ = softening_-> computeDer (x);
}
};

My question is there is better way to implement the same thing here?

I really appreciate your help.
Thank you very much.

Phu
 
M

Marcelo Pinto

Phu said:
class SofteningLaw{
    double computeVal  ( double x);
    double computeDer ( double x);

These should be:
    virtual double computeVal  ( double x) = 0; // pure virtual
    virtual double computeDer ( double x) = 0; // pure virtual
};

class LinearSofteningLaw : public SofteningLaw
{
   private:
        double k1_;
        double k2_;
  public:

    double computeVal  ( double x){return k1_ + k2_ *x;}
    double computeDer ( double x){return k2_;}

};

and other class for each softening law.

Then, in my class, I store a pointer to SofteningLaw as

class myClass{
  private:

       SofteningLaw*  softening_;
       double              val_;
       double              der_;

 public:

     void compute ( double x ){
        val_  = softening_-> computeVal (x);
        der_ = softening_-> computeDer (x);
     }

};

And yes this is a better design indeed. You should read:
http://www.objectmentor.com/resources/articles/ocp.pdf

HTH,
Marcelo Pinto
 
M

Michael DOUBEZ

Daniel said:
I'm assuming the above is a typo and it should be:

fval_ = exponentialValue ( k1_, k2_, alpha_, x );
fder_ = exponentialDerivative ( k1_, k2_, alpha_, x );


Before jumping to the OO approach, lets talk about what you have above.
All other things equal, it is better (more idiomatic, and somewhat
better performance) to use an enum to represent the different softening
laws and then in the compute function use a switch statement to jump to
the right calculations.

Now on to the question you are really asking...

Whether or not the OO solution is better depends on a number of factors.

1) How would you plan to create the softening law object? If you end up
just moving the if... else chain (or switch statement) somewhere else to
new the correct softening law then you aren't gaining anything by using
the OO approach.

2) Can/should an object be able to change its softening law at runtime?
Both the system you have above and the OO approach allows this, but is
that ability really necessary?

3) Can/should objects outside the object in question be able to
determine which softening law a particular object is using? Maybe the
object is told which softening law to use at runtime by some outside
object, maybe not...

There are rarely simple answers to design problems, even experts (some
would say, especially experts) cannot enumerate all the factors that
have to be accounted for. As such, my questions above are only the
beginning, but their answers are necessary before a determination can be
made.

I agree with your analysis but in this case, I may support the different
paradigms:
1. Make orthogonal classes representing softening policies
2. For dynamic case, make a bridge that unify them

So you would have:
class LinearSofteningPolicy
{
public:
double computeVal( double x){return k1_ + k2_ *x;}
double computeDer( double x){return k2_;}
private:
double k1_;
double k2_;
};
// ... others orthogonal classes

// interface
class ISofteningLaw{
public:
virtual double computeVal(double)=0;
virtual double computeDer(double)=0;
};

//bridge
template<class SofteningPolicy>
class SofteningLaw: public ISofteningLaw
{
public: //bridges
SofteningLaw(const SofteningPolicy& p):policy(p){}

double computeVal( double x){return policy.computeVal(x);}
double computeDer( double x){return policy.computeDer(x);}

private:
SofteningPolicy policy;
};

Now, for the generation of the various SofteningLaw<> objects, this is
up to the OP to choose it: compile-time/run-time/building-pattern ...
 
P

puzzlecracker

I agree with your analysis but in this case, I may support the different
paradigms:
   1. Make orthogonal classes representing softening policies
   2. For dynamic case, make a bridge that unify them

So you would have:
class LinearSofteningPolicy
{
   public:
     double computeVal( double x){return k1_ + k2_ *x;}
     double computeDer( double x){return k2_;}
    private:
         double k1_;
         double k2_;};

// ... others orthogonal classes

// interface
class ISofteningLaw{
   public:
     virtual double computeVal(double)=0;
     virtual double computeDer(double)=0;

};

//bridge
template<class SofteningPolicy>
class SofteningLaw: public ISofteningLaw
{
   public: //bridges
     SofteningLaw(const SofteningPolicy& p):policy(p){}

     double computeVal( double x){return policy.computeVal(x);}
     double computeDer( double x){return policy.computeDer(x);}

   private:
     SofteningPolicy policy;

};

Now, for the generation of the various SofteningLaw<> objects, this is
up to the OP to choose it: compile-time/run-time/building-pattern ...

Michael, it's a very interesting pattern (a variation of builder),
and I would like to explore it further. Why do you need to have both
static and dynamic type handling, seems an overkill?

Thanks
 
M

Michael DOUBEZ

puzzlecracker said:
I agree with your analysis but in this case, I may support the different
paradigms:
1. Make orthogonal classes representing softening policies
2. For dynamic case, make a bridge that unify them
[snip]
Michael, it's a very interesting pattern (a variation of builder),
and I would like to explore it further. Why do you need to have both
static and dynamic type handling, seems an overkill?

From the pure design point of view, IMHO it makes sense to separate the
algorithms from the need to have a polymorphic behavior. It is not like
there was a specific contract or a domain specific constraint between
MyClass and mathematical models.

That way, it removes a dependency on the interface which may then evolve
independently of the specific policies. Typically, you may want to add
some management of polymorphic behavior such as deep copy, this may be
done in the bridge at no cost for the individual policies.
 
J

James Kanze

I have implemented a code like this, in one of my class who
has a private data member: std::String name_ ..., variables
with _ mean private data members:
void compute ( double x )
{
if ( name_ == "linearSoftening" )
{
fval_ = linearValue ( k1_, k2_, x );
fder_ = linearDerivative ( k1_, k2_, x );
}
else if ( name_ == "exponentialSoftening" )
{
fval_ = linearValue ( k1_, k2_, alpha_, x );
fder_ = linearDerivative ( k1_, k2_, alpha_, x );
}
...
}
So, everytime a new softening law, say powerSoftening, is to
be added, I have to do two things:
(1) Code the two functions powerValue (...) and powerDerivative(...)
(2) Add a else if in the above void compute (double x) method.
I think this design is not object-oriented. I am thinking of
the following design. A base class
class SofteningLaw{
double computeVal ( double x);
double computeDer ( double x);
};

The functions should be virtual here, and you also need a
virtual destructor.
class LinearSofteningLaw : public SofteningLaw
{
private:
double k1_;
double k2_;
public:

double computeVal ( double x){return k1_ + k2_ *x;}
double computeDer ( double x){return k2_;}
};
and other class for each softening law.
Then, in my class, I store a pointer to SofteningLaw as

class myClass{
private:
SofteningLaw* softening_;
double val_;
double der_;

void compute ( double x ){
val_ = softening_-> computeVal (x);
der_ = softening_-> computeDer (x);
}
};
My question is there is better way to implement the same thing
here?

Maybe. There are two different patterns for this sort of
problem: the strategy pattern (which is more or less along the
lines of what you've suggested) or the template method pattern.
(I'd suggest you look up both, and learn about patterns.)
Generally speaking, the strategy pattern is more flexible,
because it allows changing the strategy dynamically; in the
template method pattern, the strategy is fixed when the object
is constructed. On the other hand, the template method strategy
is sometimes simpler, since it involves less objects.

There are also two C++ particularities to consider: unless
you're using the Boehm collector, the strategy pattern requires
some additional memory management code (and in my experience,
that code can be a real pain if you want to keep things open);
also, if you use the template method pattern, you can't call
your functions in the constructor or the destructor (which
usually isn't a problem, but I've had one case where it was).
 
J

James Kanze

puzzlecracker wrote:

[...]
From the pure design point of view, IMHO it makes sense to
separate the algorithms from the need to have a polymorphic
behavior.

In a very real way, you have polymorphic behavoir, anyway you
look at it. The question is whether resolving the polymorphism
at compile time has any advantages or not. The template method
pattern lends itself very well to compile time resolution, for
example; instead of deriving and to implement pure virtual
functions called by the "generic" class, the generic class is a
class template over a traits class, which provides the
functions.

In general, compile time resolution is less flexible (in cases
like this, anyway); on the other hand, if he's calling the
functions in a tight loop (and since this seems to be a numeric
application, that's a distinct possibility), compile time
resolution can result in significantly faster code. And if
you're even moderately familiar with templates, it's also likely
to be simpler code (although in this case at least, the
difference is very, very slight).
It is not like there was a specific contract or a domain
specific constraint between MyClass and mathematical models.

The generic class or the polymorphic class do have a contract.
 
N

nvinhphu

I agree with your analysis but in this case, I may support the different
paradigms:
   1. Make orthogonal classes representing softening policies
   2. For dynamic case, make a bridge that unify them

So you would have:
class LinearSofteningPolicy
{
   public:
     double computeVal( double x){return k1_ + k2_ *x;}
     double computeDer( double x){return k2_;}
    private:
         double k1_;
         double k2_;};

// ... others orthogonal classes

// interface
class ISofteningLaw{
   public:
     virtual double computeVal(double)=0;
     virtual double computeDer(double)=0;

};

//bridge
template<class SofteningPolicy>
class SofteningLaw: public ISofteningLaw
{
   public: //bridges
     SofteningLaw(const SofteningPolicy& p):policy(p){}

     double computeVal( double x){return policy.computeVal(x);}
     double computeDer( double x){return policy.computeDer(x);}

   private:
     SofteningPolicy policy;

};

Now, for the generation of the various SofteningLaw<> objects, this is
up to the OP to choose it: compile-time/run-time/building-pattern ...

Hi all,

I thank you for all your replies. I found myself the design of Michael
and the clear explanation of James very interesting and useful. Let me
summarize what
I have learned from you:

So, you propose to use the so-called template method pattern which
uses orthogonal
classes as policy classes and a template class SofteningLaw. It seems
to me very great but my softening law is defined at run time. I only
know write code like this:


typedef SofteningLaw <LinearSofteningPolicy> LinearSofteningLaw;
typedef SofteningLaw <ExponeSofteningPolicy> ExponeSofteningLaw;

LinearSofteningLaw softLaw;

double f = softLaw.computeVal( 3.0 );
double d = softLaw.computeDer( 3.0 );

---------------

However, how to write code in such a way that softLaw is defined
correctly at run time?

Thanks a lot for all your help.

Phu
 
M

Michael DOUBEZ

[snip]
I thank you for all your replies. I found myself the design of Michael
and the clear explanation of James very interesting and useful. Let me
summarize what I have learned from you:

So, you propose to use the so-called template method pattern which
uses orthogonal classes as policy classes and a template class SofteningLaw. It seems
to me very great but my softening law is defined at run time.

A possible implementation is the following:

class myClass{
public:

template<class SofteningPolicy>
void setSoftening(const SofteningPolicy& policy)
{
softening_.reset(new SofteningLaw<SofteningPolicy>(policy));
}

void compute ( double x ){
val_ = softening_-> computeVal (x);
der_ = softening_-> computeDer (x);
}

private:
scoped_ptr<ISofteningLaw> softening_;
};

That way, you can write:

myClass c;
c.setSoftening(LinearSofteningLaw(/* offset */ 0.1, /* slope */ 0.5));
 
P

puzzlecracker

Daniel T. wrote:
Hello everybody,
I have implemented a code like this, in one of my class who has a
private data member: std::String name_ ..., variables with _ mean
private data members:
void compute ( double x )
{
  if       ( name_ == "linearSoftening" )
  {
     fval_  = linearValue        ( k1_, k2_, x );
     fder_ = linearDerivative ( k1_, k2_, x );
  }
  else if ( name_ == "exponentialSoftening" )
  {
     fval_  = linearValue        ( k1_, k2_, alpha_, x );
     fder_ = linearDerivative ( k1_, k2_, alpha_, x );
I'm assuming the above is a typo and it should be:
      fval_ = exponentialValue        ( k1_, k2_, alpha_, x );
      fder_ = exponentialDerivative ( k1_, k2_, alpha_, x );
  }
  ...
}
So, everytime a new softening law, say powerSoftening, is to be added,
I have to do two things:
(1) Code the two functions powerValue (...) and powerDerivative(...)
(2) Add a else if in the above void compute (double x) method.
I think this design is not object-oriented. I am thinking of the
following design. A base class
class SofteningLaw{
    double computeVal  ( double x);
    double computeDer ( double x);
};
class LinearSofteningLaw : public SofteningLaw
{
   private:
        double k1_;
        double k2_;
  public:
    double computeVal  ( double x){return k1_ + k2_ *x;}
    double computeDer ( double x){return k2_;}
};
and other class for each softening law.
Then, in my class, I store a pointer to SofteningLaw as
class myClass{
  private:
       SofteningLaw*  softening_;
       double              val_;
       double              der_;
 public:
     void compute ( double x ){
        val_  = softening_-> computeVal (x);
        der_ = softening_-> computeDer (x);
     }
};
My question is there is better way to implement the same thing here?
[snip]
I thank you for all your replies. I found myself the design of Michael
and the clear explanation of James very interesting and useful. Let me
summarize what I have learned from you:
So, you propose to use the so-called template method pattern which
uses orthogonal classes as policy classes and a template class SofteningLaw. It seems
to me very great but my softening law is defined at run time.

A possible implementation is the following:

class myClass{
   public:

     template<class SofteningPolicy>
     void setSoftening(const SofteningPolicy& policy)
     {
       softening_.reset(new SofteningLaw<SofteningPolicy>(policy));
     }

     void compute ( double x ){
       val_  = softening_-> computeVal (x);
       der_ = softening_-> computeDer (x);
     }

   private:
     scoped_ptr<ISofteningLaw>  softening_;

};

That way, you can write:

myClass c;
c.setSoftening(LinearSofteningLaw(/* offset */ 0.1, /* slope */ 0.5));

Why would you use scoped_ptr as opposed to, say, share_ptr?
Personally, I have not seen the scope_ptr used that often, and wonder
why I chose to in this case.

Thanks
 
J

James Kanze

On Feb 5, 1:59 pm, Michael DOUBEZ <[email protected]> wrote:

[...]
So, you propose to use the so-called template method pattern
which uses orthogonal classes as policy classes and a template
class SofteningLaw.

I actually proposed several possibilities. No one is ideal in
all circumstances.
It seems to me very great but my softening law is defined at
run time. I only know write code like this:
typedef SofteningLaw <LinearSofteningPolicy> LinearSofteningLaw;
typedef SofteningLaw <ExponeSofteningPolicy> ExponeSofteningLaw;
LinearSofteningLaw softLaw;
double f = softLaw.computeVal( 3.0 );
double d = softLaw.computeDer( 3.0 );
However, how to write code in such a way that softLaw is defined
correctly at run time?

I'm not sure what you mean by "defined at runtime". If you mean
that the choice is only made at runtime, then you can use the
classical variants (without templates) of either the template
method pattern or the strategy pattern---the strategy pattern
will even allow changing the softLaw on an existing object. If
you mean that the actual law will only be defined at runtime (as
opposed to choosing between a set of existing laws), it becomes
more complicated. If the definition only involves choosing
among a set of possible algorithms and inserting parameters,
then your still basically within what the strategy pattern, or
even the template method pattern, can do. If it is a question
of reading some formula or equations from a configuration file
or other user input, and using that as the softLaw, you'll need
some sort of parser.
 
J

James Kanze

Why would you use scoped_ptr as opposed to, say, share_ptr?
Personally, I have not seen the scope_ptr used that often, and
wonder why I chose to in this case.

Shouldn't the question be just the opposite? Why would you use
shared_ptr when the much simpler and safer scoped_ptr
corresponds more closely to the desired semantics?
 
J

James Kanze

However, both patterns assume that some outside agent is
deciding which algorithms to use. That assumption may not be
correct in the OPs case.

I'm not sure what you mean by "outside agent". If there is more
than one algorithm in the program, a choice must be made
somewhere.
 
N

nvinhphu

Hi all,

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

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


// 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:

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.

Thanks a lot again.

Phu
 
J

James Kanze

But is the choice made from within the object, or is it made
by an object of a different type? That's what I mean by
"outside agent".

It doesn't matter. Both patterns work in both cases. For that
matter, what does it mean to make the choice? I have one widely
used class which uses the strategy pattern, choosing the
strategy according to constructor arguments. So the choice of
the actual strategy class is made in the class, but the real
choice is made by whoever passed the arguments to the
constructor.

In the case of the template method pattern, of course, something
like this would require using a static factory method, member of
the class. If the choice is internal, the strategy pattern is
usually simpler.
 
J

James Kanze

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.
 
V

Vidar Hasfjord

Hi all,

Thanks to all your support, I managed to write that code. Here it is:

[...]
  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 );

This is probably not what you want. Application::setSofteningLaw
expects a policy as an argument, not a law. By coincident passing a
law works here because both policies and the law interface use the
same function names and signatures. But the result here is double
indirection.

To avoid this problem you can either use different function names for
the interface and implementation or hide the runtime polymorphism
within the Application class, or preferably both:

class Application
{
public:
double computeDamage (double k)
{return softening_->f (k);}

double computeDeriOfDamage (double k)
{return softening_->df (k);}

template <class SofteningPolicy>
void setSofteningLaw (const SofteningPolicy& p)
{softening_.reset (new Softening <SofteningPolicy> (p));}

private:
class ISoftening
{
public:
virtual double f (double x) = 0;
virtual double df (double x) = 0;
};

template <class SofteningPolicy>
class Softening :
public ISoftening,
private SofteningPolicy
{
public:
Softening (const SofteningPolicy& p)
: SofteningPolicy (p) {}

virtual double f (double x)
{return SofteningPolicy::evalFunc (x);}

virtual double df (double x)
{return SofteningPolicy::evalDeri (x);}
};

shared_ptr <ISoftening> softening_;
};

Regards,
Vidar Hasfjord
 
V

Vidar Hasfjord

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.

I concur. If the policy is determined before the creation of the
application object and does not change during its lifetime, then this
is optimal. It provides the compiler with as much type information as
possible to optimize the code.

On the other hand, this may be too coarse for your needs. If the
policy is not known until after the construction of the application
and/or may need to change during its lifetime, then you need to use
some form of run-time polymorphism. But you do not want run-time
polymorphism in your performance-critical inner loops, so try to
express the whole algorithms (the calculation loops) in terms of
templates parameterized on policies.

For example, using your test loop as the algorithm:

class Application
{
public:
int algorithm (int n)
{
return algo_->invoke (n);
}

template <class SofteningPolicy>
void setSofteningPolicy (const SofteningPolicy& p)
{algo_.reset (new Algorithm <SofteningPolicy> (p));}

private:
class IAlgorithm
{
public:
virtual int invoke (int n) = 0;
};

template <class SofteningPolicy>
class Algorithm :
public IAlgorithm,
private SofteningPolicy
{
public:
Algorithm (const SofteningPolicy& p)
: SofteningPolicy (p) {}

virtual int invoke (int n)
{
for (int i = 0; i < n; i++)
{
double fval2 = SofteningPolicy::evalFunc (0.1);
double fder2 = SofteningPolicy::evalDeri (0.1);

//cout << " fval2: " << fval2 << ", fderi2: " << fder2 <<
"\n";
}
return 0;
}
};

shared_ptr <IAlgorithm> algo_;
};

Regards,
Vidar Hasfjord
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,189
Members
46,735
Latest member
HikmatRamazanov

Latest Threads

Top