The coding conventions are organized under various headings, and each rule is tagged according to how it affects the program code.
viability - the code will not work unless you follow this rule.
reliability - the code may not work unless you follow this rule.
maintainability - the code may be difficult to modify unless you follow this rule.
readability - the code may be difficult to understand unless you follow this rule.
reusability - the code may be less usable in conjunction with other code unless you follow this rule.
convention - the code will be unconventional unless you follow this rule.
The rules are also tagged according to whether they are:
C++ - general 'good practice' C++ coding rules.
Symbian - Symbian OS-specific rules.
S60 - S60 recommended rules.
Some entries are tagged as notes rather than rules.
C classes |
||
---|---|---|
See also classes |
||
Symbian (note) |
C class objects cannot be passed or returned by value, but only through pointers or by reference. |
|
Symbian (note) |
Passing C class objects by pointer implies either the transfer of ownership, or that the parameter is optional. To remove this ambiguity, consider overloading functions that have optional parameters. |
|
Symbian (note) |
Returning C class objects by pointer implies either the transfer of
ownership, or that the return value may be |
class invariants |
||
---|---|---|
See assertions |
coding style |
||
---|---|---|
readability |
Keep all lines fairly short, and always break the line if it goes off the edge of the screen. When you break a line, break it in a sensible place (for example, after rather than before an operator) and indent the following lines. |
|
readability |
C++ |
Use white space to group related lines of code together. |
readability |
C++ |
Use parentheses to clarify ambiguous code. |
convention |
S60 |
There should be
|
convention |
S60 |
There must be no more than 120 characters per line. Indents should be by exactly four spaces. |
convention |
S60 |
Braces should be indented according to Symbian's standards. |
compilation errors |
||
---|---|---|
reliability |
C++ |
You should have zero compiler errors, except for unavoidable warnings that are due to the libraries you are using. Ideally you should also have a minimum of Lint warnings. Fix any Lint warnings that are fixable unless blatantly foolish and counter-productive. |
constants |
||
---|---|---|
See also consts |
||
convention |
The name for a constant should be prefixed by a capital K. |
|
convention |
Constants should be implemented as either:
|
construction |
||
---|---|---|
See also constructors, destructors |
||
Symbian (note) |
C-classes are the only classes that you can |
|
Symbian (note) |
All C-class member variables are nulled on creation. |
constructors |
||
---|---|---|
See also construction, destruction, destructors |
||
viability |
Symbian |
|
reliability |
Symbian |
Constructors and |
reliability |
Symbian |
You must always have a |
reliability |
Symbian |
In the implementation of |
Symbian (note) |
For small C classes it is acceptable to have a public constructor to
allow them to be member variables of other C classes. This is normally only
done for classes without a |
|
Symbian (note) |
|
|
Symbian (note) |
Copy constructors lose their "special status" in Symbian OS. Normally
only classes with a destructor need copy constructors, and this means C-classes,
but C-classes are only instantiated via |
consts |
||
---|---|---|
See also constants |
||
reliability |
C++ |
One word of caution, however: the compiler enforces that Example: If you have member variable that is a pointer to another
object, then the compiler allows you to call Class WorstCaseScenario { public: WorstCaseScenario() : iThis(this) { } void ChangeTheWorld(); TBool InnocentLookingFunction() const { iThis->ChangeTheWorld(); } WorstCaseScenario* iThis; } |
destruction |
||
---|---|---|
See also construction, constructors, destructors |
||
Symbian (note) |
If an object is deleted twice, this is a fatal error. This will occur
if a |
destructors |
||
---|---|---|
See also construction, constructors, destruction |
||
reliability |
C++ |
In a destructor or function called from a destructor you cannot assume that the object is fully constructed, hence you must check the state of the object and cope with all situations. You must not throw any exceptions. Example: MyClass::~MyClass() { if(iObject) //might be NULL if constructor failed { iObject->Close(); delete iObject; iObject = NULL; } delete iFred; //delete NULL is allowed iFred = NULL; } |
files |
||
---|---|---|
See also header files |
||
viability |
Symbian |
Place Control IDs, and defines in |
readabillity |
Symbian |
In a resource file, always use comments! Resource file comments are written to describe the usage of the file so that localisation can be based on them. |
convention |
Naming of |
|
convention |
There should be one directory per |
|
convention |
Public header files should go in a subdirectory inc, or |
|
convention |
Documents should all go in a subdirectory docs, or |
|
convention |
All files associated with the |
|
convention |
Test files should go in a subdirectory tsrc or |
|
convention |
All other files should go in a subdirectory src, or |
|
convention |
Symbian |
In a resource file, use the same bracketing conventions you're using in your source files. |
functions |
||
---|---|---|
See also virtual functions |
||
maintainability |
C++ |
Do not use default parameters (though exceptions can be made for having one default parameter only). If you have a function with 'n' default parameters, replace it with 'n+' overloaded versions of that function. It is usual to discover that
Example: AddControl(Control& ctrl, ControlObserver* observer = 0); Becomes: AddControl(Control& ctrl); AddControl(Control& ctrl, ControlObserver* observer); Which can be improved further to become: AddControl(Control& ctrl); AddControl(Control& ctrl, ControlObserver& observer); |
readability |
C++ |
Separate functions into either
|
readability |
C++ |
Keep function bodies small. |
readability |
Symbian |
Never return an error code. Use the |
convention |
C++ |
Function names should begin with a capital letter. Normally Modifiers are expected to do something, and hence the name is in the form of an order. |
convention |
S60 |
Functions should be defined in the same order as in the header file. |
convention |
Symbian |
All inline functions should be in an |
readability |
Symbian (note) |
Function names that end in a "C" indicate that the function returns a pointer that has been pushed onto the cleanup stack. |
readability |
Symbian (note) |
Function names that end in a "D" indicate that the function call will result in the deletion of the object. |
Symbian (note) |
When a function " |
header files |
||
---|---|---|
See also files |
||
convention |
In header files, use standard anti-nesting, for example: #ifdef __CMYCLASS__ #define __CMYCLASS__ body of header #endif Always use explicit access control specifiers. List the public members
first, then the protected ones, then the private ones. List the data members
in a group after the methods. Put any "special" methods first within each
section (for example, //from CCoeControl void Draw() const; //from MObserver void Notify(); void StopObserving(); |
|
convention |
S60 |
Use |
#include |
||
---|---|---|
convention |
Put system includes first (using angle brackets), followed by local includes (using quotes). |
|
convention |
C++ |
Prefer forward declarations to |
inheritance |
||
---|---|---|
See also virtual functions |
||
maintainability |
C++ |
Never use multiple inheritance except for interfaces (that is, |
maintainability |
C++ |
Never use private or protected inheritance. Consider whether composition would be more appropriate. |
invariants |
||
---|---|---|
See also assertions |
||
See assertions. |
local variables |
||
---|---|---|
See also variables |
||
maintainability |
C++ |
Local variables should be defined as late as possible, that is near to their first use. |
maintainability |
C++ |
Never use static local variables. |
M
M classes |
||
---|---|---|
Symbian (note) |
M class objects cannot be passed or returned by value. The choice between
pointer and reference should be made according to whether a |
macros |
||
---|---|---|
See also functions |
||
reliability |
C++ |
Avoid macros. Any macros you do use should be all capitals, using underscores
to separate words. Use |
member variables |
||
---|---|---|
See also variables |
||
reliability |
C++ |
It is better by far to encapsulate member data than return references
to it . If you must return references to member data, it is better to return
a |
reliability |
C++ |
Whenever you delete member variables, you must set them to |
maintainability |
C++ |
Never have public member data. |
parameters |
||
---|---|---|
readability |
In source files, use the same parameter names as you had in the header file. |
|
readability |
C++ |
Never use ellipsis notation, that is, |
pointers |
||
---|---|---|
reliability |
C++ |
Never use pointer arithmetic. |
reliability |
C++ |
Never use pointer casts. Unfortunately, sometimes libraries you are
using force you to cast return values. In this case encapsulate the cast in
a function call, and use standard C++ casts rather than C style casts (for
example, |
reliability |
S60 |
Initialize all pointers to |
reusability |
Symbian |
Use descriptors and other specialized classes instead of pointers when storing data or handling strings. |
convention |
S60 |
Check for non-null pointers via |
postconditions |
||
---|---|---|
See assertions. |
preconditions |
||
---|---|---|
See assertions. |
R classes |
||
---|---|---|
See also destructors |
||
viability |
Symbian |
You cannot push R-class objects onto the cleanup stack, hence they must not have a destructor. |
viability |
Symbian |
You shouldn't pass R class objects by value. Since R class variables are system resources you shouldn't make copies of them. |
reliability |
Symbian |
R classes must initialize all member data in the constructor. You cannot rely on members being zeroed. |
reliability |
Symbian |
R class objects must not be created via new. |
Symbian (note) |
It is generally necessary to "open" and "close" R-type objects, and hence you see code like this: RFile file; file.OpenL(); TRAPD(err,file.ReadL()); if(err) { file.CloseL(); User::Leave(err); } //etc. etc. This is inefficient, and makes code quite unreadable, being (in effect) a return to the era of checking return values for error codes. There is a simple method for bypassing this, shown in the following example: class SRClassCleanup { public: static void OpenLC(RFile& aFile) { User::LeaveIfError(aFile.OpenL); CleanupStack::PushL(TCleanupItem (ReleaseRFileOnCleanup,&aFile)); } private: static void ReleaseRFileOnCleanup(TAny* aObject) { REINTERPRET_CAST(RFile*,aObject)->Close(); } //repeat for all R-Classes in your project. }; Then we can simplify the previous example to the following (assuming
we've derived from RFile file; OpenLC(file); file->ReadL(); //etc. etc. CleanupStack::PopAndDestroy();//close file |
T classes |
||
---|---|---|
viability |
Symbian |
Since T class objects cannot be pushed onto the cleanup stack, they must not have a destructor as you cannot ensure that it is called in all circumstances. |
viability |
Symbian |
T class objects must not be created via new. |
Symbian (note) |
T class objects are returned by value, and passed by reference or value. |
TBool types |
||
---|---|---|
Symbian (note) |
The compiler will not allow you to compare TBool types with |
templates |
||
---|---|---|
reliability |
C++ |
Templates should be used only for defining universal containers. Any template should be tested carefully on the target platform. |
reliability |
C++ |
Templates should never be used in conjunction with virtual functions. |
types |
||
---|---|---|
viability |
Symbian |
Always use Symbian OS types, for example, |
viability |
Symbian |
Don't use the explicit type forms (for example |
readability |
C++ |
For conversion between base types, always use explicit casts - it clarifies your code and removes warnings. |
convention |
The name for the enumeration type should have a capital Use relevant, meaningful, and unambiguous names for |
variables |
||
---|---|---|
See also local variables, member variables |
||
reliability |
C++ |
Only a single variable declaration should be made per statement. |
convention |
Symbian |
Put the pointer or reference indicator next to the type name, with no separating space. |
convention |
Symbian |
Variable names start with (some or none) Symbian OS prefixes (i, a, C, M, T, R, E, K, S), followed by concatenated words (that is, no underscore separator), the first letter of each word being capitalised, followed by (possibly) Symbian OS postfixes (L, C, D). The only exception to this rule is that local variables have a lower case first letter to distinguish them from functions. Don't use numbers or abbreviations in names (except for test code). |
convention |
Symbian |
Variable names should be abstract nouns like |
convention |
Symbian |
Local variable names should start with a lower case letter. |
convention |
Symbian |
Parameter names should be prefixed with a lower case "a", followed by an upper case letter. |
convention |
Symbian |
Member data names should be prefixed with a lower case "i", followed by an upper case letter. |
virtual functions |
||
---|---|---|
See also functions, inheritance |
||
viability |
C++ |
You should never call a virtual function from within a constructor or destructor. |
reliability |
C++ |
Never overload virtual functions. |
reliability |
C++ |
When implementing a virtual function you often need to call the base class implementation. When you scope the call you should use your immediate base class: SportsCar::DoSomething() { FastCar::DoSomething(); //code here } |
reliability |
S60 |
Virtual functions should not be inline, except for destructors. |
maintainability |
C++ |
When implementing a virtual function you often need to call the base class implementation. This should normally be done first or last: SportsCar::DoSomething() { FastCar::DoSomething(); //code here } or SportsCar::DoSomething() { //code here FastCar::DoSomething(); } and not: SportsCar::DoSomething() { //code here Car::DoSomething(); //some more code here } |
readability |
C++ |
Never change the visibility (public/protected/private) when overriding a virtual function. |
reliability |
C++ (note) |
In an overridden function you cannot make any more assumptions than the preconditions of the base class implementation and your own class Invariants. |