Is Schrödinger's Cat
Object-Oriented? - Appendix B
Writing C++ Code II: TParticle,
TNucleon and TProton Classes
This Appendix presents C++ code for some of the examples discussed in
this work, such as the abstract base class TParticle and the concrete
classes TNucleon , TProton and TNeutron. Here
we have not attempted to produce the "best" class design, but
just to provide an illustration of some of the OM features using C++.
In the file Particle.h we declare the abstract base class TParticle
which encompasses common features of objects of type TParticle
#include <Vector3D.h>
class TParticle
{
public:
TParticle (TVector3D initialMomentum);
TParticle ();
virtual ~TParticle ();
virtual TVector3D GetMomentum () const;
virtual void SetMomentum (TVector3D newMomentum);
virtual long GetNumber () const = 0;
protected:
TVector3D fMomentum;
};
The class TParticle contains just one data member, fMomentum,
which is protected. Protected means that only derived classes can access
this member. Alternative designs could have chosen to include, say, other
particle attributes such as kMass, kElectricCharge, etc.
In our design these other data members are included in some of the derived
class (e.g., TProton and TNeutron). TParticle
is an abstract base class, thus it cannot be instantiated. An abstract
base class has at least one pure virtual function. A pure virtual member
function (e.g., GetNumber()) is not implemented in the base class
but derived classes must provide its implementation (this is indicated
by appending " = 0" after the method's declaration). Derived
classes (such as TChargedParticle, TPhoton, TNucleon,...)
usually implement constructors/destructors, and may add additional methods
(such as AbsorbPhoton(), EmitPion( ), ...). Additional
data members may also be added (such as kMass, kElectricCharge
,...).
Virtual functions (such as the get and set methods, and the destructor
of class TParticle) allow derived classes to replace (override)
these functions' implementation polymorphically. Suppose that the method
GetElectricCharge() is defined in the class TChargedParticle.
Then, the derived classes TElectron , TProton and TNeutron
would then inherit this method but should provide different implementations
(i.e., override this method). For example, GetElectricCharge()
returns 0 for aNeutron, 1 for aProton and -1 for anElectron.
The source file Particle.C contains the implementation of the GetMomentum()
and SetMomentum() methods and is given below
#include <Particle.h>
TVector3D TParticle::GetMomentum() const
{
return fMomentum;
}
void TParticle::SetMomentum(TVector3D aMomentum)
{
fMomentum = aMomentum;
}
There could be several intermediate classes between TParticle
and TNucleon (such as THadron, TMultipletSU4,
...). Since there are not many interesting additional OO features to illustrate,
and for a sake of simplicity, we derive TNucleon directly from
the abstract base class. Thus, in another file, Nucleon.h we declare the
class TNucleon, which is a concrete class (it can be instantiated),
and directly derives from (i.e., is a subclass of) TParticle
#include <Particle.h>
#include <Pion.h>
class TNucleon : public TParticle {
public:
TNucleon (TVector3D initialMomentum);
TNucleon ();
virtual ~TNucleon ();
virtual double GetMass () const;
virtual long GetNumber () const;
void EmitPion (TPion aPion);
void AbsorbPion(TPion aPion);
private:
static const double kMass;
static long fgNumber;
};
The first (#include) lines indicate to the compiler that information
declared in the headers <Particle.h> and <Pion.h> will be required.
The source file Nucleon.C follows
#include <Nucleon.h>
const double TNucleon::kMass = 1833.15;
long TNucleon::fgNumber = 0;
TNucleon::TNucleon()
{
TVector3D aVector3D;
fMomentum = aVector3D;
fgNumber ++; //increase by one the nucleon counter
}
TNucleon::TNucleon(TVector3D initialMomentum)
{
fMomentum = initialMomentum;
fgNumber ++;
}
TNucleon::~TNucleon()
{
fgNumber --; //decrease by one the nucleon counter
}
double TNucleon::GetMass() const
{
return kMass;
}
void TNucleon::AbsorbPion(Pion aPion)
{
fMomentum += aPion.GetMomentum();
}
void TNucleon::EmitPion(Pion aPion)
{
fMomentum -= aPion.GetMomentum();
}
long TNucleon::GetNumber() const
{
return fgNumber;
}
The class TProton (which derives from TNucleon)
is declared in the header Proton.h
#include <Nucleon.h>
class TProton : public TNucleon {
public:
TProton (TVector3D initialMomentum);
TProton () ;
virtual ~TProton();
virtual long GetElectricCharge() const;
virtual long GetNumber() const;
private:
static const long kElectricCharge;
static long fgNumber;
};
Most of the data and methods of TProton are inherited
from TNucleon, so they have already been implemented. Hence little
additional work is required. Constructors/destructor are overridden and
the method GetElectricCharge() is implemented in the source file
Proton.C
#include <Proton.h>
const long TProton:: kElectricCharge = 1 ;
long TProton:: fgNumber = 0;
TProton::TProton() : Nucleon() { fgNumber++;}
TProton::TProton(TVector3D initialMomentum):TNucleon(initialMomentum )
{ fgNumber++;}
TProton::~TProton() { fgNumber--;}
long TProton::GetElectricCharge() const
{
return kElectricCharge;
}
For the class TNeutron code is identical to that of the TProton
with the replacement TNeutron by TProton, and the value
for the electric charge, kElectricCharge, zero instead of one.
For the code given in the Appendices to compile and work, the reader
must implement the class TNeutron as discussed above, and also
declare and implement TPion which could directly derive from TParticle.
In this case, TPion is almost identical to TNucleon replacing
Nucleon by Pion (the methods EmitPion() and AbsorbPion()
are not required). This provides the reader all ingredients necessary to
describe, in the main program, interactions between protons and neutrons.
For example, one might have
#include <Proton.h>
#include <Neutron.h>
#include <Pion.h>
void main(){
TPion aPion(aMomemtum_Q); //create a pion with aMomentum_Q
TProton aProton((aMomemtum_P1); //a proton with aMomentum_P1
TNeutron aNeutron((aMomemtum_K1); //and a neutron with aMomentum_K1
aProton.EmitPion(aPion); //proton and neutron interact
aNeutron.AbsorbPion(aPion); //exchanging a pion
}
to describe a pion exchange process pictured in a Feynman diagram identical
to that of Fig. 3 replacing electron by neutron, and photon by pion.
As stated before the design of the Appendices are just for illustration.
One of the drawbacks of our design is the presence of the global quantity
fgNumber, the number of particles of a given type. This information
is available to all particles of a given type (in a more sound design,
a given particle should not be aware of how many particles of the same
type are in the universe). In a more mature design, one might have, for
example, an Universe object which acts as a manager of the particles and
their interactions. This object might have a "clock", might keep
track of the number of particles of each type and of their interactions,
might apply forces to particles, etc.
|