6.2. Defining a new class

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. )
      }
 15 
    
      CLASSNAME() {}// A constructor without an argument
      ~CLASSNAME() {}// A destructor
    };
 20 
    LIBECS_DM_INIT( CLASSNAME, DMTYPE );
    

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

6.2.2. Filename

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

6.2.3. Include Files

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.

6.2.4. DM Macros

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( DMTYPE, CLASSNAME ) 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 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( DMTYPE, CLASSNAME ) exports the class 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.

6.2.5. Constructor And Destructor

DM objects are always instantiated by calling the constructor with no argument. The destructor is defined virtual in the base class.

6.2.6. Types And Declarations

6.2.6.1. Basic types

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

6.2.6.2. Pointer and reference types

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

For example, RealCref is equivalent to write const Real&. Using these typedefs is recommended.

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.

6.2.6.3. Limits and other attributes of types

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.

6.2.7. Polymorph class

A Polymorph object can be constructed from and converted to any of Real, Integer, String, types and PolymorphVector class.

6.2.7.1. Construct a Polymorph

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

6.2.7.2. Getting a value of a Polymorph

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

Note

If an overflow occurs when converting a very big Real value to Integer, a ValueError exception?? is thrown. (NOT IMPLEMENTED YET)

6.2.7.4. PolymorphVector

PolymorphVector is a list of Polymorph objects.

6.2.8. Other C++ statements

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.