5. Class 

5.1 Class Declaration (Header File)
  • Public data should not be used without overriding efficiency justification. 
  • Provide access methods (Get/Set) for data as needed for access by other classes or code (e.g., GetPosition(), SetRadius()) 
  • Declare a destructor to be virtual if there is any possibility that a class could be derived from this class (particularly if there are any virtual methods declared for this class). 
  • Declare a method to be virtual if you expect it to be overridden by the derived classes. The most prominent reason why a virtual function will be used is to have a different functionality in the derived class. The difference between a non-virtual member function and a virtual member function is: the non-virtual member functions are resolved at compile time in what is known as static or compile - time binding, and the calls to the virtual member functions are resolved during run-time using a mechanism known as dynamic binding.

Notes: 

Since GMAT supports plug-in modules that may be written by groups that do not have write access to the repository, we ought to code GMAT so that these outside groups can extend the system without either granting write access or making a local fork version for the purpose of making the methods extensible through a virtual declaration.

  • When declaring a function, put its return type on the same line as the function name. However, if the return type is very long, it is preferable to put the method name on the next line, lined up with the list of methods.


int GetParamCount();
virtual std::string GetRefObjectName(const Gmat::ObjectType type) const; virtual const StringArray& GetRefObjectNameArray(const Gmat::ObjectType type);

  • Include preprocessor commands to avoid multiple definitions of items in a header file. Capitalize the preprocessor command the same way as the class name for easier future text substitution.


For the AnalyticalModel class:

#ifndef AnalyticalModel_hpp #define AnalyticalModel_hpp ... // class definition or type definitions (etc.) ... #endif // AnalyticalModel_hpp

5.1.1 Required Methods for a Class

Always include the following methods for each class, to avoid having the compiler declare them for you. Declare them private (and possibly unimplemented) to limit or disable usage. 

  • default constructor
  • copy constructor
  • destructor
  • assignment operator
5.1.2 Class Method/Function Declaration Layout

The class declaration should include public, protected, and (if applicable) private sections (in that order). Since the user of the class needs the class interface, not the implementation, it make sense to have the public interface first.

Example:

class SolarSystemBody { public: ... protected: ... private: ... };

5.1.3 Include
  • Include statements must be located at the top of a file only. 
  • Include statements should be sorted and grouped. Sorted by their hierarchical position in the system with low level files included first. 
  • Use C++ libraries, instead of C libraries, whenever possible. For example,

use #include <iostream> instead of #include <stdio.h> 

Notes: 

This guideline may be ignored in cases of optimization, where the C library routines are proved to be more efficient than the C++ library routines)

  • For system include files, put a comment explaining why a particular file was included. 
  • Header files should be included only where they are needed and whenever they are needed for clarity. i.e. the user should be able to easily follow the code to determine the origin of methods or variables used in the code. 
  • Wherever possible, extern declarations (of global data) should be contained in source files instead of header files. 
  • Use extern "C" if referencing C external variables for functions, when necessary. 
  • When extern data or constants are included in a header file, remember to compile and link the .cpp file(s) that contain the actual definitions of the constants or externs into your program.

For Portability

You should also avoid using directory names in the include directive, since it is implementation-defined how files in such circumstances are found. Most modern compilers allow relative path names with / as separator, because such names has been standardized outside the C++ standard, for example in POSIX. Absolute path names and path names with other separators should always be avoided though.


The file will be searched for in an implementation-defined list of places. Even if one compiler finds this file there is no guarantee that another compiler will. It is better to specify to the build environment where files may be located, since then you do not need to change any include-directives if you switch to another compiler.

#include "inc/MyFile.h" // Not recommended #include "inc\MyFile.h" // Not portable #include "/gui/xinterface.h" // Not portable #include "c:\gui\xinterf.h" // Not portable 

5.1.4 Inlining
  • Be careful about inlining. If your compiler has an inlining switch, prefer the use of that to actually including methods' implementations in the header file. (Also, compilers are not up-to-speed on compiling when methods are inlined in the header - in some cases, a compiler will generate a larger program because of this). 
  • Inline member functions can be defined inside or outside the class definition. The second alternative is recommend. The class definition will be more compact and comprehensible if no implementation can be seen in the class interface.


class X { public: // Not recommended: function definition in class bool insideClass() const { return false; } bool outsideClass() const; };
// Recommended: function definition outside class inline bool X::outsideClass() const { return true; }

5.1.5 Class Header File Layout

Header files should include items in this order: 

  • SVN keyword -Class name banner -Header file prolog -Preprocessor #ifndef command -System include files -Application include files -Constant declarations -Class declaration -Non-member functions (global functions) -Preprocessor #endif command
Example:

//$Id$ //----------------------------------------------------------------------------- // Class Name //----------------------------------------------------------------------------- // Header File Prolog // ... // ... //----------------------------------------------------------------------------- #ifndef ClassName_hpp #define ClassName_hpp
#includes ... Constant declarations ...
class ClassName { public: ... protected: ... private: ... };

//------------------------------------- // global declarations //------------------------------------- ... ...
#endif // ClassName_hpp

5.2 Class Definition (Source File)
5.2.1 Constructors
  • Avoid doing any real work in a constructor. Initialize variables and do only actions that can't fail. Object instantiators must check an object for errors after construction.
  • Avoid throwing exceptions from constructors.
  • All member data should be initialized in a constructor, not elsewhere, whenever possible.
5.2.2 Exceptions
  • Use exceptions for truly exceptional conditions, not for message passing (i.e. use exceptions when processing cannot continue without user action).
For Efficiency
  • Catch exceptions by reference.
5.2.3 Class Method/Function Definition Layout
  • Methods/functions should be defined in the order in which they appear in the class declaration.
  • Always initialize all variables.
  • The function signature, its return type, and the argument names in the definition (implementation) should match its declaration (prototype) exactly.
  • When defining a function's implementation, a long return type may go on a line above the function name.

int AttitudeModelClass::GetModelNumber() { ... }

CosineMatrix

CosineMatrix::GetInverse() const { ... } 

For Efficiency
  • Minimize the number of constructor/destructor calls: this means minimize the number of local objects that are constructed; construct on returning from a method, rather than creating a local object, assigning to it, and then returning it; pass large objects by const reference; etc. 
  • Initialize member data in an initialization list. It is necessary that the order of the items in the initialization list match the order of declaration; also, initialize base class data first (if it is not already initialized in the base class code)


MaString::MaString(const char *string1, unsigned int len1, const char *string2, unsigned int len2) : lengthD(len1 + len2), caseSensitiveD(true) { ... }

5.2.4 Class Source File Layout

The source file should contain the following sections: 

  • SVN keyword -Class name banner -Source file prolog


#includes -#defines -Static variable initialization -Source file method prolog followed by implementation

Example:

//$Id$ //----------------------------------------------------------------------------- // Class Name //----------------------------------------------------------------------------- // Source File Prolog // ... //----------------------------------------------------------------------------- #includes ... #defines ...
//----------------------------------- // static data //----------------------------------- const Real ClassName::REAL_UNDEFINED = -987654321.0123e-45; const Integer ClassName::INTEGER_UNDEFINED = -987654321;
//----------------------------------- // static functions //-----------------------------------
//----------------------------------- // public methods //-----------------------------------
//----------------------------------------------------------------------------- // source file method prolog // ... //-----------------------------------------------------------------------------
Implementation code ... ...
//----------------------------------- // protected methods //-----------------------------------
//----------------------------------------------------------------------------- // source file method prolog // ... //-----------------------------------------------------------------------------
Implementation code ... ...
//----------------------------------- // private methods //-----------------------------------
//----------------------------------------------------------------------------- // source file method prolog // ... //-----------------------------------------------------------------------------
Implementation code ... ...
//-----------------------------------------------------------------------------