E-Cell Simulation Environment Version 3.1.100 User's Manual (Draft: Dec. 18, 2003) | ||
---|---|---|
Prev | Chapter 6. Creating New Object Classes | Next |
A new object class can be defined by writing a C++ source code file with some special usage of C++ macros.
Here is a boilarplate template of a DM file, with which you
should feel familiar if you have a C++ experience. Replace
DMTYPE
, CLASSNAME
, and
BASECLASS
according to your case.
Example 6-1. CLASSNAME.cpp; a boilarplate DM template.
#include <libecs/libecs.hpp> #include <libecs/BASECLASS
.hpp> 5 USE_LIBECS; LIBECS_DM_CLASS(CLASSNAME
,BASECLASS
) { public: 10 LIBECS_DM_OBJECT(CLASSNAME
,DMTYPE
) { // ( Property definition of this class comes here. ) } 15CLASSNAME
() {}// A constructor without an argument~CLASSNAME
() {}// A destructor }; 20 LIBECS_DM_INIT(CLASSNAME
,DMTYPE
);
DMTYPE
, CLASSNAME
and BASECLASS
First of all you have to decide basic attributes of the class you are going to define; such as a DM type (Process, Variable, System, or Stepper), a class name, and a base class.
DMTYPE
DMTYPE
is one of DM base classes
defined in E-Cell Simulation Environment Process,
Stepper,
Variable, and
System.
CLASSNAME
CLASSNAME
is a name of the
object class.
This must be a valid C++ class name, and should end with the
DMTYPE
name. For example, if you are
going to define a new Process class and
want to name it Foo
, the class name may
look like FooProcess
.
BASECLASS
The class your class inherits from.
This may or may not be the same as the DMTYPE
, depending on whether it is a direct
descendant of the DM base class.
The name of the source file must be the same as the CLASSNAME
with a trailing '.cpp' suffix. For example, if the CLASSNAME
is FooProcess
, the file name must be
FooProcess.cpp.
The source code can be divided into header and source
files (such as FooProcess.hpp and
FooProcess.cpp), but at least the
LIBECS_DM_INIT
macro must be placed in the source file
of the class (FooProcess.cpp).
At least the libecs header file
(libecs/libecs.hpp) and a header file of
the base class (such as
libecs/BASECLASS
.hpp)
must be included in the head of the file.
You may notice that the template makes use of some
special macros: USE_LIBECS
,
LIBECS_DM_CLASS
,
LIBECS_DM_OBJECT
, and
LIBECS_DM_INIT
.
USE_LIBECS
declares use of
libecs library, which is the core
library of E-Cell Simulation Environment, in this file after the line.
LIBECS_DM_CLASS
LIBECS_DM_OBJECT(
should be
placed on the top of the class definition part (immediately
after '{' of the class). This macro declares that this is a
DM class. This macro makes it dynamically instantiable, and
automatically defines
DMTYPE
,
CLASSNAME
)getClassName
() method. Note that
this macro specifies public: field inside, and thus anything
comes after this is placed in public. For clarity it is a
good idea to always write public: explicitly after this
macro.
LIBECS_DM_OBJECT( DMTYPE, CLASSNAME ) public:
LIBECS_DM_INIT(
exports the
class DMTYPE
,
CLASSNAME
)CLASSNAME
as a DM class of type
DMTYPE
. This must come after the
definition (not just a declaration) of the class to be
exported with
a LIBECS_DM_OBJECT
call.
DM objects are always instantiated by calling the constructor with no argument. The destructor is defined virtual in the base class.
The following four basic types are available to be used in
your code if you included libecs/libecs.hpp
header file and called the USE_LIBECS
macro.
Real
A real number. Usually implemented as a double precision floating point number. It is a 64-bit float on Linux/IA32/gcc platform.
Integer
A signed integer number. This is a 64-bit long int on Linux/IA32/gcc.
UnsignedInteger
An unsigned integer number. This is a 64-bit unsigned long int on Linux/IA32/gcc.
String
A string equivalent to
std::string
class of the C++ standard
library.
Polymorph
Polymorph is a sort of universal type (actually a class) which can *become* and *be made from* any of Real, Integer, String, and PolymorphVector, which is a mixed list of these three types of objects. See the next section for details.
These types are recommended to be used over other C++ standard types such as double, int and char*.
For each types, the following typedefs are available.
TYPEPtr
Pointer type. (== TYPE*)
TYPECptr
Const pointer type. (== const TYPE*)
TYPERef
Reference type. (== TYPE&)
TYPECref
Const reference type. (== const TYPE&)
To declare a new type, use DECLARE_TYPE
macro. For example,
DECLARE_TYPE( double, Real );is called inside the system so that RealCref can be used as const double&.
Similary, DECLARE_CLASS can be used to enable the typedefs for a class. Example:
DECLARE_CLASS( Process );enables ProcessCref ProcessPtr etc.. Most classes defined in libecs have these typedefs.
To get limits and precisions of these numeric
types, use std::numeric_limits<>
template class in the C++ standard library. For instance, to
get a maximum value that can be represented by the
Real type, use the template class like this:
#include <limits> numeric_limits<Real>::max();See the C++ standard library reference manual for more.
A Polymorph object can be constructed from and converted to any of Real, Integer, String, types and PolymorphVector class.
To construct a Polymorph object, simply call a constructor with a value:
Polymorph anIntegerPolymorph( 1 ); Polymorph aRealPolymorph( 3.1 ); Polymorph aStringPolymorph( "2.13e2" );A Polymorph object can be constructed (or copied) from a Polymorph:
Polymorph aRealPolymorph2( aRealPolymorph );
The value of the Polymorph
objects can be retrieved in any type by using as<>
() template method.
anIntegerPolymorph.as<Real>(); // == 1.0 aRealPolymorph.as<String>(); // == "3.1" aStringPolymorph.as<Integer>(); // == 213
![]() | If an overflow occurs when converting a very big Real value to Integer, a ValueError exception?? is thrown. (NOT IMPLEMENTED YET) |
getType
(), changeType
()
PolymorphVector is a list of Polymorph objects.
The only limitation is the DM_INIT
macro, which exports a class as a DM class, can appear only
once in a compilation unit which forms a single shared library
file.
Except for that, there is no limitation as far as the C++ compiler understands it. There can be any C++ statements inside and outside of the class definition including; other class definitions, nested classes, typedefs, static functions, namespaces, and even template<>.
Be careful, however, about namespace corruptions. You may want to use private C++ namespaces and static functiont when a class or a function declared outside the DM class is needed.