Sie sind auf Seite 1von 28

C++ Programming Standards

Table

Of Contents

Memory management (New and Delete)...................................................................1


Operator new and operator delete.............................................................................1
Cautions......................................................................................................................1
Allocation Failures......................................................................................................1
Arrays.........................................................................................................................1
Pointers.......................................................................................................................2
Data Type Considerations..........................................................................................3
Casts or Type Conversions........................................................................................3
#define........................................................................................................................3
ENUM.........................................................................................................................3
References (&)...........................................................................................................4
Pointers (*)..................................................................................................................4
Function Pointers........................................................................................................4
Typedef.......................................................................................................................5
INT..............................................................................................................................5
CHAR..........................................................................................................................5
LONG..........................................................................................................................6
SHORT.......................................................................................................................6
Foundation Large INT................................................................................................6
Foundation String and Foundation String Variable....................................................6
Collections..................................................................................................................6
Data Sources..............................................................................................................7
Structures...................................................................................................................7
Global Data...................................................................................................................7
Location........................................................................................................................7
Section 1 - Classes..................................................................................................7
Components of a Class...............................................................................................9
Header File.................................................................................................................9
Declaration of Class Functions and Data...............................................................10
Public........................................................................................................................10
Protected..................................................................................................................10
Private.......................................................................................................................11
Inheritance................................................................................................................11
Includes......................................................................................................................12
Format of Include Statement....................................................................................12
Which files to Include...............................................................................................12
Preventing Multiple Inclusion of Headers with #define............................................12
Contents of the Include File......................................................................................13
Constructor Considerations.....................................................................................14
Initialization Order.....................................................................................................14
Indicating Status of Instantiated Objects..................................................................14
Copy Constructors....................................................................................................16
1

Destructor Considerations.......................................................................................17
Required Functions..................................................................................................18
Naming.....................................................................................................................18
Inline Functions........................................................................................................19
Templates.................................................................................................................19
Basic Elements of Functions....................................................................................19
Function Recommendations.....................................................................................27
Specific Types of Functions......................................................................................28
Friend..........................................................................................................................29
Non-Portable Classes...............................................................................................29
New Operator...........................................................................................................29
Constructor...............................................................................................................29

Memory management (New and Delete)


Operator new and operator delete
Always use the same form of new and delete.
string *stringPtr1 = new string;
string *stringPtr2 = new string[100];
delete stringPtr1;
delete [] stringPtr2;

// delete an object
// delete an array of
// objects

Prefer using auto_ptr (smart pointers). That will avoid any leaks being caused by non-usage of
delete.

Arrays
An array is allocated with operator new using brackets. When using the delete operator for an array,
empty brackets are required in the statement. If the bracket is not included , the destructor is not
called for all elements of the array. If the brackets are not included in the delete when it is required, a
memory leak will result.
For example:
//
// Declare the pointer to a list of rectangle pointers.
//
rectangle **rectangle_ptr;
//
// Call new for the array of rectangles.
//
rectangle_ptr = new rectangle *[ 100 ];
for ( idx = 0; idx < 100; ++idx )
{
rectangle_ptr[ idx ] = new rectangle();
}
//
// The call to delete contains brackets.
//
delete[] rectangle_ptr;
//
// This is a MEMORY LEAK - a dangerous situation!
//
delete rectangle_ptr;

Smart Pointers
Smart pointers are a smart way of avoiding leaks. Where ever possible, use auto_ptr (C++
standard library provided smart pointer).
If you are not acquainted, then follow this link to smart pointer.
Small implementation of auto_ptr (it can be greatly customized according to the needs).
Disadvantage of smart pointer they cant be compared against NULL
If(ptr == 0) or
If(ptr) or if(!ptr) //where ptr is auto_ptr

Is not possible.

Casts or Type Conversions


Casts should be used sparingly since it is possible for some data to be lost in the conversion. It can
be dangerous to make a cast from a data type that is smaller to a data type that is longer because of
alignment issues. For example, converting a char pointer to an int pointer may not work when the
char is on an odd byte boundary. Also, it can be dangerous to make a cast from a data type that is
longer to a data type that is smaller because data can be lost.
Explicitly specify a cast when dealing with arithmetic expressions involving both signed data types
and unsigned data types.
For example:
int
unsigned int
unsigned int
y = ( unsigned

x;
y;
z;
int )x + z;

#define
Defines should be declared in the class header or source file.
Define names are suffixed with _d when the name is lowercase letters, or the define name can be all
uppercase letters with no suffix.
Do not use the #define directive for numeric values since this hinders debugging code. Enumerated
types are used for numeric values. The use of defines as a function is discouraged. If a define can
be implemented in any other way (i.e., a function, an enumerated type, etc.), use the other way
instead of creating a define.
Prefer Const and Inline to define where ever possible.
5

ENUM
Use enums for constants that are local to a class. Enum names can be prefixed with the name of
the class to avoid collisions.
Enumerated types are declared in the class header or source file.
Whenever a numeric value is used in code statements, consider setting up an enum with that
numeric value for use in the code statements. This allows easy modification of the numeric value in
multiple locations when the enum value is changed. Also, the enum has the advantage of
documenting the purpose of the number.
Note: Enumerated values must not be defined as a string of two or more characters.

Function Pointers
Declaring a typedef for a pointer to a function is recommended for purposes of readability.
For example (note: header file and source file combined for simplicity):
class shape
{
public:
typedef int ( shape::*fn_shape_area_fncb )( void );
enum area_measure_type_e
{
square_inches = 1,
square_feet
= 2,
square_yards = 3,
square_miles = 4
};
int
int
int
int

pi_;
radius_;
length_;
width_;

int area_circle( void )


{
return pi_ * radius_ * radius_;
}
int area_rectangle( void )
{
return length_ * width_;
}
int convert( int area,
area_measure_type_e area_measure )
{
//
// Conversion would take place here.
//
return area;
}
int size( fn_shape_area_fncb area_fncb_ptr,
area_measure_type_e area_measure )
{

int
area;
area = ( this->*area_fncb_ptr )();
return convert( area, area_measure );
}
void calc_size( void )
{
//
// Area_circle and area_square are function calls.
//
size( &fn_shape::area_circle, square_feet );
size( &fn_shape::area_rectangle, square_yards );
}
};

Collections
Collections are used to hold many different objects, but the order that the iterator and collection are
created and destroyed are important.
The collection should be created before the iterator. When collections are to be cleared for use again
later in the processing, the clr_and_destroy() function should be invoked. If the collection is no
longer needed, delete all iterators first, then delete the collection without using the clr_and_destroy()
function.
The deletion of the collection in the destructor is more efficient than calling clr_and_destroy() then
deleting the collection, which takes more instructions. The collection destructor will check for any
objects to be deleted, therefore those steps will be duplicated in the clr_and_destroy() and the
destructor of the collection.

Data Sources
The order of creation and deletion is important for all the classes used with data sources.
The order for creation of the data source classes should be in the following order:
1. Data source.
2. Selectors.
3. Rows, cursors, inserters, deleters, and updaters. These can be in any order.
The order for deletion of the classes associated with data sources should remove the classes from
the stack in the reverse order from how they were added. The order for the deletion of the data
source classes should be in the following order:
1. Rows, cursors, inserters, deleters, and updaters.
2. Selectors.
3. Data Source.

Structures
If a new structure is required, it is located in the class definition that requires it.

The allocated size of a structure may change from machine to machine dependent upon that
machines alignment needs for specific data types.

Global Data
The use of global data must be minimized. Principles of data encapsulation must be employed to
minimize global data. It is preferable to have data that is private to an object as opposed to global
data.

Location
Implementation classes belonging to a component are located on a specific component directory.
The interface class for the component has the appropriate header on the include directory.
General Transaction Data Elements (TDEs) and component specific TDEs are to be located on the
general TDE subdirectories (the butde directory contains the header files and the butdes directory
contains the implementation files).

Section 1

- Classes

A class definition consists of a header file and a source file.


Only one class should be defined per source file.
Within class declarations, the public, protected, and private data members and member functions
will be declared in that order. If one of these is not required it is omitted. There should only be one
section for each of these in the include file.
Classes must not define public data. This violates the principle of data encapsulation. Exceptions to
this might include 'simple' classes that are not intended to hide their implementation.
The ways that a client can use a class is defined by the class interface. How the client interfaces into
the class is important when considering which function to place in a class. A minimal yet complete
class interface is an advantage since the resulting classes are more manageable and are easier to
comprehend.

Components of a Class
Header File
The header file declares the name of the class, the data members, and member functions for the
class.
According to our standards, no code statements are placed in the header files. The one exception
to this rule is inline functions and template classes which do not have source files. Inline functions
should contain no more than one statement.

Layout of the Header File


The following order is used for header files.

Proprietary Comment Box.


History Section.
#ifndef for preventing multiple inclusion.
#define for preventing multiple inclusion.
#includes in alphabetical order with #ifndef statements.
#define for Component ID (Component headers only).
Class forward declarations in alphabetical order.
Class Description Comment Box.
class keyword.
Class name declaration.
Class inheritance if applicable.
public: keyword.
Public - defines in alphabetical order.
Public - enums in alphabetical order.
Public - friends in alphabetical order.
Public - structures.
Public - default constructors with function comment boxes.
Public - other constructors with function comment boxes.
Public - copy constructors with function comment boxes.
Public - destructors with function comment boxes.
Public - overloaded operators in alphabetical order with function comment boxes.
Public - overloaded friend operators in alphabetical order with function comment boxes.
Public - member functions in alphabetical order with function comment boxes.
protected: keyword.
Protected - defines in alphabetical order.
Protected - enums in alphabetical order.
Protected - structures.
Protected - default constructors with function comment boxes.

Protected - other constructors with function comment boxes.


Protected - copy constructors with function comment boxes.
Protected - destructors with function comment boxes.
Protected - overloaded operators in alphabetical order with function comment boxes.
Protected - overloaded friend operators in alphabetical order with function comment boxes.
Protected - member functions in alphabetical order with function comment boxes.
Protected - data members in alphabetical order.
private: keyword.
Private - defines in alphabetical order.
Private - enums in alphabetical order.
Private - structures.
Private - other constructors with function comment boxes.
Private - copy constructors with function comment boxes.
Private - overloaded operators in alphabetical order with function comment boxes.
Private - member functions in alphabetical order with function comment boxes.
Private - data members in alphabetical order.
End of class declaration
Code for inline functions
End of #ifndef.

Declaration of Class Functions and Data


Obviously, all functions and data declared for the class are available for that class itself to use.
However, there are restrictions for other classes based upon the area in which the function is
declared in the class being used. Data hiding is one of the big advantages of C++.

Public
All functions that are available to any other classes are declared as public. Data should not be
public.

Protected
Functions and data that are available to derived classes are declared here. If a class attempts to
use a protected function or data member for a class that it does not inherit from, a compiler error
results.
Protected data members are preferred over private data members where derived classes can use
the data members directly without incurring any performance penalty and avoiding having to code all
the get/set functions that would be required otherwise to deal with the data members. The get/set
functions would match exactly the type of the data member, so if there is a change to the data
member type, the get/set function would change as well. The destructor must be either public or
protected. It can not be private or there can not be a derived class.

10

Private
Functions and data that are to be available only to the class itself are declared private. If a class
attempts to use a private function or data member for another class, a compiler error results.
Always use the private keyword even though it is not necessary. This makes the level of access
more visible and easier to discern.
Functions, constructors and operators that should not be publicly used should be defined private.
This generates a compiler error if an attempt is made by a client to use a function, constructor or
operator that is declared private.

Inheritance
Public Inheritance
When a class has an is-a relationship with another class, the relationship is translated to C++ code
using public inheritance.

Private Inheritance
Private inheritance should be used rarely. Scott Meyers refers to private inheritance as an "is
implemented in terms of" relationship between two classes. This type of relationship is not the result
of a design consideration for a class. It is only an advantage when coding a class because it can use
the other class functions.

11

Includes
Format of Include Statement
When declaring include files in a header file, use the format <file.h> instead of "file.h".
Do not include directories in file name specifications. To better facilitate porting files across
environments, directories must not be included in the file name specifications.
Do not put sections in the filename on include statements. Include statements should only contain
the filename. The Tandem extension of appending only the section to be included is unacceptable
as it is non-standard and non-portable.
//
// This is unacceptable because of the section included, and because
// of the missing #ifndef statement.
//
#include <shape.h(draw_section)>
//
// This is acceptable.
//
#ifndef SHAPE_H
#include <shape.h>
#endif

Which files to Include


Only the include files that are required for the interface are put in the header file. If possible, class
forward declarations are used instead of including the entire class header file.
The remainder of the include files are located in the source (.cpp) file. The files needed by the
implementation are located in the source file. This helps hide the implementation and produces
better encapsulation.

Preventing Multiple Inclusion of Headers with #define


A single header file can only be included once in the course of a compile. Defines are used within
every header file to prevent a header from being included multiple times. The use of this method is
required in all header files.
The define name is based upon the class header file name. This define must be all uppercase
letters.
Example for header file:
#ifndef SHAPE_H
#define SHAPE_H
<include files>
<class declaration>

12

#endif

// if not defined SHAPE_H

Example for source file:


#ifndef SHAPE_H
#include <shape.h>
#endif

For third party code (system libraries and STL included), the following example applies:
#ifndef ALGO_H
#include <algo.h>
#ifndef ALGO_H
#define ALGO_H
#endif
#endif

The define name in the third party header is ignored, and the engineer defines the include guard
according to standards in the source that uses the #include. The standards for defining the third
party include guard is to use the name of the include file in all uppercase letters. Replace the .h
with _H. So, <algo.h> becomes ALGO_H for the define. If a file does not have a .h, still include
an _H. For example, a header file named <clocale> becomes CLOCALE_H.

Contents of the Include File


No code should go into the include file. Even if a function consists of a one line statement the code
should be located in the source file. The exception to this is for inline functions and template
classes.

13

Constructor Considerations
Classes must have a default constructor. If a constructor is not defined, the compiler automatically
provides a default constructor. If a default constructor is not valid for a class, place it in the private
section to prevent it from being used. This applies to the copy constructor and assignment operator,
also.
If a class has an instance function (e.g. a Component Bridge), no constructors should be public.

Initialization Order
List initialization data members in the order that they are declared. This avoids confusion over the
order that members are initialized. According to the C++ standard, members are initialized in the
order that they are declared, not the order that they appear in the initialization list. Data members
should be declared in alphabetical order, so initialization lists should be in alphabetical order unless
there is a reason for the data members not to be in alphabetical order.
Do not build constructors that have dependencies on the order of initialization of data members or
static objects.
Use the initialization mechanism within constructors for base classes and all data members. This
reduces the risk of an invalid state after successful construction.
For example:
bu_rectangle::bu_rectangle( const int lgth,
const int width ) :
fn_shape(),
lgth_( lgth ),
width_( width )
{
}

Indicating Status of Instantiated Objects


Obviously, object status values are not returned from constructors.
Instead, functions are provided for access to a given status. Note that it is possible that an operator
could be overloaded to perform the same type of functionality, but that is not as intuitive as an
explicit member function. The following three examples show correct and incorrect constructors.
This example shows the best way. No status value is returned in the constructor, and the member
function used to determine if the object is valid is very intuitive.

14

For example:
//
// This is correct
//
int
width = 5;
int
lgth = 5;
bu_rectangle square( lgth, width );
if ( square.area() < 0 )
{
return false;
}
//
//
//
.
.
.

Otherwise, the square object is valid, so continue processing.

This example is wrong. The constructor of the file object returns a value in the status variable. The
client is required to define a status variable to hold the return status and then test the status.
For example:
//
// This is wrong
//
int
width = 5;
int
lgth = 5;
int
stat;
bu_rectangle square( lgth, width, stat );
if ( !stat )
{
return false;
}

This example is wrong. Even though the constructor does not return a value, it is not very intuitive
because the object has overloaded the "!" logical not operator.
For example:
//
// This is wrong
//
int
width = 5;
int
lgth = 5;
bu_rectangle square( lgth, width );
if ( !square )
{
return false;
}

15

Copy Constructors
All classes should contain a copy constructor. It is especially important for classes that contain
pointer members. If copy semantics are allowed, the copy constructor must be made public. If they
are not allowed the copy constructor must be made private. Private copy constructors must be
defined but not necessarily implemented.
The default "copy constructor" generated by the compiler performs a bit-wise copy of member data.
This is a shallow copy. For shallow copies, pointers are copied, but the data being pointed to is not
copied. A deep copy is a copy where the data that the pointers are pointing to is copied as well. Be
aware that shallow copies can cause data members for different objects to point to the same data.
This could produce unexpected results when the data is deleted. The first object may delete the
data, and the second object that still has a pointer to the memory is not aware of the memory being
deallocated. If the second object attempts to access the data, the process will abend.
For example:
bu_rectangle::bu_rectangle( const bu_rectangle &rectangle )
{
//
// This is a deep copy of the coordinate_ptr_. A copy constructor for
// the data member can be used.
//
coordinate_ptr_ = new bu_coordinate( rectangle.coordinate_ptr_ );
//
// This is a deep copy of the figure_txt_ptr_. A new statement is executed
// for the pointer followed by the copying of the value.
//
figure_title_ptr_ = new char[ ( sizeof( figure_title_def ) + 1 ) ];
strcpy( figure_title_ptr_, rectangle.figure_title_ptr_ );
}

16

Destructor Considerations
Destructors are declared as virtual for the sake of the derived classes. It is important that the
destructors be called properly when the derived class is destroyed via a pointer to the parent class.
When a destructor is declared as virtual, the derived class destructor causes the parent class
destructor to be invoked.
Destructors should release all the resources owned by the object or leaks could result. It is not
necessary to put logic in destructor for singletons, since the destructor should never get invoked.

17

Required Functions
The required functions for any class are default constructors, copy constructors, and assignment
operator functions.

Default Constructor
Classes must contain default constructors. If this function is not required, it can be placed in the
private area to prevent its usage.

Copy Constructor
Classes must contain copy constructors. If this function is not to be used by clients, it can be placed
in the private area to prevent its usage.

Assignment Operator Functions


The assignment operator function is similar to the copy constructor function. A shallow copy is
dangerous for a class with pointers as data members. Assignment operator functions are defined so
that deep copies are produced when the assignment operator is used.
Assignment operators must check for assignment to self. Assignment to self should not be executed
as a memory leak could result.
Assignment operators must return a const reference to the assigning object which allows multiple
assignments within a single statement.
For example:
//
// Dimensions of a cube.
//
height = length = width;

Naming
Member function names should be descriptive of the service that it provides.
For example:
int bu_rectangle::area_get( void );
void fn_shape::fill( void );
void fn_shape::draw_outline( void );

All functions that have the same name should have similar behavior, varying only in the number
and/or types of parameters.

18

Inline Functions
Use of inline functions should be considered carefully because they cannot be debugged. However,
the use of inline functions generally increases the performance of the code. Inline functions normally
consist of one line of code. A more complicated function should not be made inline for the purposes
of debugging. Examples of functions that may meet this criteria are mutator and accessor functions.
Inline is a recommendation to the compiler, so there is no guarantee that the function will be made
inline by the compiler. Do not use #define instead of inline functions.

Templates
Template classes contain the function declarations and the function definitions in the header.

Basic Elements of Functions


Return Type
When a function has a return type, the data returned must not be a pointer to a local variable. Once
the function returns, the local variables within the function are deallocated when the function pops off
of the stack.

Function Arguments (parameters)


Data encapsulation implies that member functions must never return pointers or references to data
that have less visibility than the function. So for example, a protected member function should not
return to the client a pointer to a private data member.
Pass and return objects by reference instead of by value. Passing an object by value invokes the
use of copy constructors, and it creates temporary objects.
Avoid functions with a large number of arguments so that function are less complicated. Try to keep
the number of arguments for a function less than or equal to eight. Each parameter should be listed
on a separate line in the function declaration.
Use the same parameter names in the declaration (header) and definition (code). This increases the
clarity of the correspondence between declaration and definition.

19

Temporary Objects

Minimize the number of temporary objects that are created. Temporary objects are often created
when objects are returned from functions or when objects are passed by value to functions. The
creation and deletion of temporary objects can adversely affect performance.
Default Arguments

Use default arguments cautiously. The use of default arguments makes code less clear and
increases the potential of creating problems when a function is overloaded. Use a default value for
the last parameter only if it can be kept as the last parameter.
Variable Arguments

Use overloaded functions instead of functions with a variable number of arguments. Variable
argument lists defeats type checking and therefore are not advised. The use of ellipses is not
recommended, but it can be used if a particular problem requires it.
It is acknowledged that some Tandem NSK calls require variable arguments.
Const Arguments

Use constant references (const &) instead of call-by-value whenever possible when declaring nonscalar function arguments. This is more efficient when passing back non-scalar arguments since it
avoids creating a copy of the argument on the stack. In the case of an object, creating a copy
involves invoking the copy constructor and a destructor.

Local Variables
Declaration

In general, variables are declared immediately before the statement block in which the variable is
used. The use of stack space for local variables is preferred over heap space.
For example:
//
// This is wrong.
//
int
x_ofst;
int
y_ofst;
if ( point_ptr_ )
{
for ( x_ofst = 0; x_ofst <= x_ofst_lmt_; ++x_ofst )
{
for ( y_ofst = 0; y_ofst <= y_ofst_lmt; ++y_ofst )
{
x_coordinate_ptr_->calc( x_ofst );
y_coordinate_ptr_->calc( y_ofst );
point_ptr_->coordinate_set( x_coodinate_ptr_, y_coordinate_ptr_ );
}
}
}
//
//

This is correct.

20

//
if ( point_ptr_ )
{
int
x_ofst;
int
y_ofst;
for ( x_ofst = 0; x_ofst <= x_ofst_lmt_; ++x_ofst )
{
for ( y_ofst = 0; y_ofst <= y_ofst_lmt; ++y_ofst )
{
x_coordinate_ptr_->calc( x_ofst );
y_coordinate_ptr_->calc( y_ofst );
point_ptr_->coordinate_set( x_coodinate_ptr_, y_coordinate_ptr_ );
}
}
}

Do not declare the same variable name in different scope because of the ambiguities it causes in
inspect.
For example:
//
// This is wrong. Look at the variable called posn_ofst.
//
if ( point_ptr_ )
{
if ( x_coordinate_ptr_ )
{
int
posn_ofst;
posn_ofst = point_ptr_->posn_get();
x_coordinate_ptr_->coordinate_set( posn_ofst );
if ( y_coordinate_ptr_ )
{
int
posn_ofst;
posn_ofst = point_ptr_->posn_get();
y_coordinate_ptr_->coordinate_set( posn_ofst );
}
}
}

21

For example:
//
// This is correct.
//
if ( point_ptr_ )
{
if ( x_coordinate_ptr_ )
{
int
posn_ofst_x;
posn_ofst_x = point_ptr_->posn_get();
x_coordinate_ptr_->coordinate_set( posn_ofst_x );
if ( y_coordinate_ptr_ )
{
int
posn_ofst_y;
posn_ofst_y = point_ptr_->posn_get();
y_coordinate_ptr_->coordinate_set( posn_ofst_y );
}
}
}

It is acceptable to limit the scope of variables in a member function. Declaring a variable with the
smallest possible scope improves the readability of the code and results in performance
improvements if the variable is not needed. If a variable is to be used no matter what occurs in a
function, it should be declared at the beginning. If, however, its use is dependent on certain
situations it can be declared only when needed.
Variables must each be declared in a separate declaration statement. This makes code more
readable and can be useful to some editing tools.
For example:
//
// This is wrong.
//
fn_coordinate *x_coordinate_ptr,
*y_coordinate_ptr;
//
// This is correct.
//
fn_coordinate *x_coordinate_ptr,
fn_coordinate *y_coordinate_ptr;

Initialization

Initialize variables to default values only if required. It is only necessary to initialize variables to
default values if a condition occurs where the variable can be interrogated without previously being
set.

Program Statements
Expressions

22

Use parentheses to make expressions evaluate in the correct order. Do not depend upon
assumptions concerning evaluation order.
Break Usage in loop-type statements

It is recommended to use break to exit a loop to avoid the use of flags.


Switch statements

The default case within the switch statement must be used to prevent unpredictable behavior for the
statement. Break statements are required at the end of a block of case statements when the
engineer does not want the execution to continue processing the next set of case label statements.
For statements

A for statement should use lower limits that are a valid value and upper limits that are not a valid
value. The purpose of this rule is to avoid the case where the body is executed one too many or one
too few times.
For example:
//
// This is right.
//
for ( x_coordinate = lower_limit; x_coordinate < upper_limit; ++x_coordinate )
{
}

If statements

If possible, use "return" in if-then-else statements to reduce nested levels.


If there is no code that needs to be executed after the execution of an if then else statement, return
can be used to reduce the levels of nesting.
For example:
//
// Poorly nested code.
//
if ( dimension == two_dimensional )
{
z_coordinate_ptr_ = 0;
return true;
}
else
if ( dimension == three_dimensional )
{
z_coordinate_ptr_ = new fn_coordinate();
return true;
}
return false;

The above block of code could be written as follows to reduce the levels of indentation and to make
the code more readable, but can only be used when there is a return in the body of the if statement.
23

//
// This is correct.
//
if ( dimension == two_dimensional )
{
z_coordinate_ptr_ = 0;
return true;
}
if ( dimension == three_dimensional )
{
z_coordinate_ptr_ = new fn_coordinate();
return true;
}
return false;

When there is more than one simple statements inside the body of the if or else, a set of braces
must be used to define the body of the statement.
if ( fnct_typ == encrypt )
{
//
// Check for the exact length required to be converted into ASCII
// for AKB and non-AKB format.
//
if ( is_ver_284() )
{
buf_lgth = 32;
}
else
{
buf_lgth = 90;
}
}
else
{
//
// Function if Translate. Set the length to be converted into
// ASCII accordingly.
//
if ( is_ver_284() )
{
buf_lgth = 52;
}
else
{
buf_lgth = 168;
}
}

Another example of an if statement is one which can be used when a switch statement cant be
implemented. The following type else if statements can only be used when there are no if
statements in the body of the else if statement.
if ( dimension == two_dimensional )
{
z_coordinate_ptr_ = 0;
}
else
if ( dimension == three_dimensional )
{

24

z_coordinate_ptr_ = 0;
}
else
if ( dimension == one_dimensional )
{
z_coordinate_ptr_ = 0;
}

GOTO

Never use goto.

Assert Statements

Assert is a macro which detects coding errors. Only coding errors are to be detected with assert
statements. For example, a read error that occurs on a file is not tested with an assert statement.
Assert statements are compiled by defining the NDEBUG symbol. When the NDEBUG symbol is
defined, the assert statements are replaced with an empty body of logic (essentially, no logic), so the
statements are compiled out of the resulting executable.
The assert statement is passed an expression that must evaluate to the boolean value of true.
When the assert expression fails, the assert macro logic invokes the appropriate exception. This
may involve displaying an error message, aborting the process, whatever is appropriate.
The assert statements are linked to the documented preconditions and postconditions of each
member function.
For example:
//
//Thepreconditionisthattherectanglepointerinputargument
//cannotbezero.
//
//Thepostconditionisthattherectanglemustbedrawn.
//
voidshape::draw(const bu_rectangle * const rectangle_ptr )
{
assert( rectangle_ptr != 0 );
construction_loc = rectangle_ptr->construct_it();
assert( construction_loc != 0 );
}

Assert statements are to be included in each member function that has a precondition and/or
postcondition documented in the header file. The precondition assert statements are usually at the
beginning of a function, but this is not always the case. It is appropriate to have an assert statement
after some work has been done in the function. Deciding where to put the assert statement is
different for each function, so it is up to the discretion of the engineer to pick the appropriate
placement for the assert statement.
An assert statement should never do any work or change the behavior of the function. They can
only perform tests and should not do any assignment type operations.

25

Function Recommendations
Inheritance
Classes should be written so functions are declared as virtual for the purpose of inheritance.
Overload functions in the parent class only when the parent function is declared as virtual.
Redefining a parent class function that is not a virtual function is dangerous and should be avoided.
When the function of an object is invoked, a different function is called depending on whether the
object pointer is defined as the parent class or the child class.
A derived class must not redefine the data type for a default parameter within an overloaded
function. Doing so will produce unexpected results since the default values are resolved at compile
time while the virtual function calls are resolved at run-time.

Overloading
Functions

Do not change the purpose of a function via overloading of the function. All versions of a function
should have the same purpose.
Avoid overloading a function where the signature differs between a pointer and a numeric type.
Incorrect results can occur when the client invokes the function using a numeric value.
For example:
//
// This is wrong.
//
void fill_texture::repeat_interval_set( int a )
{
}
void fill_texture::repeat_interval_set( char *ptr )
{
}
//
// Confusion results here!
//
repeat_interval_set( 0 );

26

Operators
Operator overloading must be done in a manner that is consistent with the original intent of the
operator. If the overloading of an operator is confusing or misleading, clients could easily use the
operator incorrectly. Use operator overloading carefully.

Exception Handling
For functions that may raise an exception, be prepared to handle any possible exceptions. This
results in more robust code.
For functions that return error values, check the error code before proceeding. Code that does so is
more robust.
Do not base logic upon assumptions regarding how the code is written within the invoked functions.

Specific Types of Functions


Const Functions
Declare member functions as const whenever possible to insure that data members are not modified
by the client using the function. For example, accessor functions can be declared as const functions.

Virtual Functions
Make all member functions virtual. Making all member functions virtual enables customization using
inheritance.
Function that are not to be virtual are Constructors, Copy Constructors, Assignment Operators,
Inline Functions and Static Functions.

Accessor Functions (get functions)


Accessor member functions should have names of the form: <value>_get(). These are functions
which provide access to an object attribute. The word value is replaced with the name of the
attribute being retrieved.
For example:
int repeat_interval_get( void );

A Transaction Data Element (TDE) accessor function should return a boolean value.
For a TDE with multiple data fields which are set separately and the valid flag is set to true when
some of these data fields are not present, a is_xxxx_set boolean function should be invoked before
attempting to obtain data for the field that is not included in valid flag setting logic.

27

Mutator Functions (set functions)


Mutator member functions should have names of the form: <value>_set(). These are functions which
set an object attribute. The word value is replaced with the name of the attribute being altered.
For example:
void repeat_interval_set( int interval_value );

Friend
Minimize the use of friend. The use of friends violates the principles of encapsulation and makes
classes more difficult to maintain.

Non-Portable Classes
Do not use non-portable classes in the platform independent code. An example would be an
ofstream class, which is not supported on the IBM CICS platform.

New Operator
Product classes should check the CSM Factory before creating class objects with the new operator.
The key to the CSM Factory should equal the class name in lower case with quotes. For example:
crd_impl_ptr_ = ( crd_impl * )fn_csm_factory::create( "crd_impl" );
if ( !crd_impl_ptr_ )
{
crd_impl_ptr_ = new crd_impl;
}

Constructor
Product classes should use the default constructor (no parameters) to allow the class to be replaced
using the CSM Factory. If the class provides an instance function, the constructor should be
protected. This forces other classes to use the instance function.

28

Das könnte Ihnen auch gefallen