Hi,
I previously posted a question asking for suggestions on my class
design. My original code consisted of a pure virtual base class Body
which contained a number of integration algorithms which are applied
to the Body. Generally only one integration algorithm is used via an
integrate() method, which selected the integration algorithm to call
depending on a variable.
Code similar to the following was suggested as a improvement. I have
modified it so it should compile on gcc. In the posters example
acceleration had also been moved from Body to Integrator, in the wider
context of my code I don't think I can do this. Here is the new class
design:
#include <iostream>
#include <ostream>
using namespace std;
class Body;
class IntegratorImpl;
class Integrator {
public:
Integrator() {}
~Integrator() {}
enum IntegratorType
{
kNone, kEuler, kVerlet, kLeapFrog
};
bool integrate();
void selectIntegrato r(IntegratorTyp e t, Body &b);
private:
IntegratorImpl *m_impl;
};
class Body
{
public:
Body() {}
bool integrate() { return m_integrator.in tegrate(); }
void selectIntegrato r( Integrator::Int egratorType type )
{
m_integrator.se lectIntegrator( type, *this );
}
Integrator m_integrator;
double position_x, position_y, position_z;
double velocity_x, velocity_y, velocity_z;
double acceleration_x, acceleration_y, acceleration_z;
static const double dt = 1;
};
class IntegratorImpl {
public:
IntegratorImpl( Body &b) : m_body( &b ) {}
virtual bool integrate() = 0;
protected:
Body *m_body;
};
class EulerIntegrator : public IntegratorImpl {
public:
EulerIntegrator (Body &m_body) : IntegratorImpl( m_body) {}
bool integrate() {
// do Euler integration
m_body->velocity_x += m_body->acceleration _x * m_body->dt;
m_body->position_x += m_body->velocity_x * m_body->dt;
// etc...
cout << "Euler integration called" << endl;
return true;
}
};
class VerletIntegrato r : public IntegratorImpl {
public:
VerletIntegrato r(Body &m_body) : IntegratorImpl( m_body) {}
bool integrate() {
// do Verlet integration
// etc...
cout << "Verlet integration called" << endl;
return true;
}
};
// Class LeapfrogIntegra tor similar to EulerIntegrator not shown
void Integrator::sel ectIntegrator(I ntegratorType type,Body &body) {
switch( type ) {
case kEuler:
m_impl = new EulerIntegrator (body);
break;
case kVerlet:
m_impl = new VerletIntegrato r(body);
break;
default:
// throw? your choice
break;
}
}
bool Integrator::int egrate() {
return m_impl->integrate();
}
class Planet : public Body {
public:
Planet() {}
double calcForce(Plane t &p)
{
acceleration_x = (p.position_x - position_x) * (p.position_x -
position_x);
}
};
// Class SimpleHarmonic, not shown defined similar to Planet
int main() {
Planet p;
Planet p2;
// SimpleHarmonic s;
p.selectIntegra tor( Integrator::kEu ler );
p2.selectIntegr ator( Integrator::kVe rlet );
// s.selectIntegra tor( Integrator::kLe apfrog );
cout << "planet,eul er: ";
p.integrate();
cout << "planet,ver let: ";
p2.integrate();
// cout << "simpleharmonic ,leapfrog: ";
// s.integrate();
return 0;
}
In this code an Integrator object is stored by Body, Integrator is
provided with a reference to Body which it uses to access the data
from Body it needs to perform the integration (this should probably be
encapsulated better than it is in the example code) and a value
specifying which type of integrator to use. The Integrator object
creates an IntergratorImpl object depending on this type. And when
Integrator.inte grate() is called, the call is passed on to the
underlying implementation.
I believe this is an improvement over my original code but that this
solution would construct lots of largely empty integrator objects,
which only contain a pointer to Body. Is it possible to avoid this?
And also perhaps the overhead caused by the Integrator object? Are
there other solutions I should consider?
The previous posters, and any additional advice is appreciated.
The original thread is here:
http://groups.google.ie/group/comp.l...03c8ebcd5cbe9d