![]() | ![]() Main Index |
| MCA2 Programmer's Guide | ||||
|---|---|---|---|---|
| Prev | Fast Backward | Chapter 6. MCA coding standards | Fast Forward | Next |
This section contains some guidelines on how to write well formed MCA2 code.
We propose to define functions and variables in the order public, protected and private, each time beginning with functions and ending with variables. We recommend not to declare variables as public. Better define inline function in order to access them.
Example 6-6. A sample class declaration.
class tNewClass::public tBaseClass
{
public:
tNewClass();
~tNewClass();
inline int GetMyProtectedVariable() { return a_protected_variable; }
int an_ugly_public_variable;
protected:
int CallMe();
int CallMeLater();
int a_protected_variable;
private:
int ForInternalUseOnly();
float i_am_private;
}; |
Just like names, all comments written in MCA2 code must be written in english . Please adhere strictly to this rule - it is very difficult for international students to work on code that is commented in other languages.
There are three different ways to signal the start of a comment:
Using '//'. This comments out all following characters until a newline is encontered. Use this to comment out small code parts or write a sigle line comment.
Using '/*'. This comments out all following characters until a '*/' token is encontered. Use this to comment out large code parts or write multi-line comments.
Using '/*!'. This comments out all following characters until a '*/' token is encontered. When you use this token, the doxygen tool automatically extracts the comment and builds the class documentation from it. Use this type of comment to describe the function of classes, methods or variables. The appropiate place to put such comments is above the commented entity.
Example 6-7. Sample comments.
//! Short description of tImageLoader
/*! A more detailed description of tImageLoader, which
spans two lines and says nothing.
*/
class tImageLoader
{
public:
/*! \param num_streams the number of streams to use
* \param delay How many milliseconds to wait before loading the next image
*
* This method constructs a tImageLoader object. This comment is not so useful.
*/
tImageLoader(unsigned int num_streams, float delay) {
// create a helper object
tImage image = new tImage("default.bmp");
/* Comment out this entire block
printf("tImageLoader:ctor>> Some useful information\n");
printf("tImageLoader:ctor>> Some more useful information\n");
printf("tImageLoader:ctor>> Even more useful information\n");
*/
}
};
|
It is a very good idea to choose different names for instance variables (variables declared as members of an object) and other, temporary variables. This helps the reader to find out whether some expression uses a temporary variable (like a function parameter) or some 'global variable' declared in the class definition. It also helps you to avoid problems that can arise when a temporary variable shadows some instance variable with the same name (see the following example).
Example 6-8. Naming conflict between temporary and instance variables.
class tNewClass::public tBaseClass
{
public:
tNewClass();
~tNewClass();
void MyNewMethod(int value);
protected:
int last_value;
};
tNewClass::MyNewMethod(int value)
{
int last_value;
.
.
. some code goes here
.
.
// save the value in the instance variable
last_value = value;
// ERROR! The temporary variable 'last_value' is used instead of the instance variable. Data will be lost when the method ends.
} |
The best way to avoid this naming conflict is somewhat controversial and we therefore offer three different possibilities:
Use a prefix like 'param_' or 'temp_' for all variables that are no class members.
Prepend an underscore to all instance variable names.
Always access instance variables using the
this pointer.
Example 6-9. Accessing instance variables.
class tNewClass::public tBaseClass
{
public:
tNewClass();
~tNewClass();
void MyNewMethod(int function_argument);
void AnotherMethod(int param_variable_three);
protected:
float instance_variable_one;
float _instance_variable_two;
float variable_three;
};
tNewClass::MyNewMethod(int function_argument)
{
float temp = sqrt(function_argument);
this->instance_variable_one = temp; // using 'this->'
_instance_variable_two = temp; // using underscore
}
tNewClass::AnotherMethod(int param_variable_three)
{
variable_three = param_variable_three; // using param_ prefix
}
|
In any case, we strongly recommend that you always choose different names for instance and temporary variables. Also, use only one of the methods presented above in your code. Pick the one you like the most and stick to it!
C++ offers a special way to initialize instance variables in the class constructor.
This allows for better inheritance and the declaration of const variables
without directly specifying their value upon declaration. Therefore, use this special initialization syntax.
Example 6-10. Initializing instance variables.
class tNewClass::public tBaseClass
{
public:
tNewClass();
tNewClass(String& name);
~tNewClass();
protected:
float _instance_variable_one;
int _instance_variable_two;
String _my_name;
};
tNewClass::tNewClass():_instance_variable_one(1.4),
_instance_variable_two(3),
_my_name("default_name")
{
printf("tNewClass constructed.\n");
}
tNewClass::tNewClass(String& name):_instance_variable_one(1.4),
_instance_variable_two(3),
_my_name(name)
{
printf("tNewClass constructed.\n");
} |
#defineThe #define directive may only be used to compile code depending on user
defined switches.
In order to define constant values we recommend to use constant variables of a specific type.
This allows the compiler to do type checking and generate warning or even errors. It also allows to
limit the scope of the const variables.
Sense() and Control()
The Sense() and Control()
functions are special functions provided by the
tModule class. Inside these functions, you can
access the module interfaces using the four methods
SensorInput, SensorOutput,
ControllerInput and
ControllerOutput.
In general, it
is a bad idea to call any of the two
Controller*-functions in the
Sense() method or the
Sensor*-functions in the
Control() method. This might create circular data
paths and cause strange data oscillations whenever multiple Parts are
connected. Therefore, avoid mixing these functions; use buffer
variables instead.