C++ coding style

Met.3D’s C++ coding style is based on the Qt Coding Style, which we have modified in some parts.

Note

Reference: Some of the following text and examples have been taken and adapted from the Qt Coding Style. Please see the referenced document for the original style.

Note

You may encounter lots of code in Met.3D that breaks the following conventions. This is mostly old code, which will be reformatted with time. For new code, please use the following conventions.

General file structure

Both header (*.h) and source (*.cpp) files start with a common header that indicates license and copyright information of the file:

 1/******************************************************************************
 2**
 3**  This file is part of Met.3D -- a research environment for the
 4**  three-dimensional visual exploration of numerical ensemble weather
 5**  prediction data.
 6**
 7**  Copyright 2016 ...
 8**
 9**  Met.3D is free software: you can redistribute it and/or modify
10**  it under the terms of the GNU General Public License as published by
11**  the Free Software Foundation, either version 3 of the License, or
12**  (at your option) any later version.
13**
14**  Met.3D is distributed in the hope that it will be useful,
15**  but WITHOUT ANY WARRANTY; without even the implied warranty of
16**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17**  GNU General Public License for more details.
18**
19**  You should have received a copy of the GNU General Public License
20**  along with Met.3D.  If not, see <http://www.gnu.org/licenses/>.
21**
22*******************************************************************************/

After the header, C++ header files follow the structure:

 1#ifndef MYMET3DCLASS_H
 2#define MYMET3DCLASS_H
 3
 4// standard library imports
 5#include <memory>
 6
 7// related third party imports
 8#include <GL/glew.h>
 9
10// local application imports
11#include "gxfw/mactor.h"
12
13namespace Met3D
14{
15
16/**
17 @brief The class MMyMet3DClass is briefly described in this Doxygen
18 comment.
19*/
20class MMyMet3DClass
21{
22public:
23    MMyMet3DClass();
24    ~MMyMet3DClass();
25
26    /**
27     This comment documents the following function in Doxygen style. All
28     methods should be briefly described in the C++ header file. Do not
29     repeat the description in the source file.
30    */
31    void setMyProperty(int someNumber);
32
33protected:
34    // protected method and variable definitions ...
35
36    int myProperty;
37
38private:
39    // private method and variable definitions ...
40};
41
42} // namespace Met3D
43
44#endif // MYMET3DCLASS_H

After the header, C++ source files follow the structure:

 1#include "mymet3dclass.h"
 2
 3// standard library imports
 4#include <iostream>
 5
 6// related third party imports
 7#include <log4cplus/loggingmacros.h>
 8
 9// local application imports
10#include "util/mutil.h"
11
12using namespace std;
13
14namespace Met3D
15{
16
17/******************************************************************************
18***                     CONSTRUCTOR / DESTRUCTOR                            ***
19*******************************************************************************/
20
21MMyMet3DClass::MMyMet3DClass()
22    : myProperty(42)
23{
24    // ... do something ...
25}
26
27
28MMyMet3DClass::~MMyMet3DClass()
29{
30    // ... do something ...
31}
32
33
34/******************************************************************************
35***                            PUBLIC METHODS                               ***
36*******************************************************************************/
37
38void MMyMet3DClass::setMyProperty(int someNumber)
39{
40    myProperty = someNumber;
41}
42
43
44/******************************************************************************
45***                          PROTECTED METHODS                              ***
46*******************************************************************************/
47
48// ... some definitions ...
49
50
51/******************************************************************************
52***                           PRIVATE METHODS                               ***
53*******************************************************************************/
54
55// ... some definitions ...
56
57
58} // namespace Met3D

Indentation

  • Use four (4) spaces for indentation.

  • Do not use tabs.

Blank lines

  • Two (2) blank lines follow each method definition in the source files.

  • Use a blank line to separate comments that describe not only the next code line but the next section of code.

Variables declaration and naming

We use the same variable declaration style as the Qt Coding Style:

  • Each variable is declared on a separate line.

  • Avoid short or meaningless name (e.g. r, rwqrr, laksjdiuqk).

  • Only use single character names (e.g. i) for counters and temporaries, where the meaning is obvious.

  • For pointers or references, always use a single space between the type and * or &, but no space between the * or & and the variable name.

// Wrong:
int a, b;
MTask *c, *d;
MTask * t1;

// Correct:
int height;
int width;
MTask *nameOfThisTask;
MTask *nameOfThatTask;
MTask &myFancyTaskReference;
  • Wait to declare a variable until it is needed.

  • Use camel-case: Variables and functions start with a lower-case letter. Each consecutive word in a variable’s name starts with an upper-case letter.

  • Avoid abbreviations.

// Wrong:
short Cntr;
char ITEM_DELIM = ' ';

// Correct:
short counter;
char itemDelimiter = ' ';
  • Classes always start with an upper-case letter.

  • Public classes start with an ‘M’ (e.g. MTask) followed by an upper case letter.

  • Acronyms are camel-cased (e.g. MHsvColourBar, not MHSVColourBar).

Line breaks

  • Keep all code and comment lines shorter than 80 columns. (Hint: Most IDEs provide an option to highlight the 80-character-border.)

  • Place commas at the end of a wrapped line, operators at the beginning of a new line.

// Wrong:
if (longExpression +
    otherLongExpression +
    otherOtherLongExpression)
{
    // .. some code ..
}

// Correct:
if (longExpression
    + otherLongExpression
    + otherOtherLongExpression)
{
    // .. some code ..
}

Braces

  • Use separate lines for braces.

  • Also use braces if a code block only contains a single line.

// Wrong:
if (condition) {
    // .. some code ..
} else {
    // .. some code ..
}

// Correct:
if (condition)
{
    // .. some code ..
}
else
{
    // .. some code ..
}

Parentheses

  • Group expressions by using parentheses.

// Wrong:
if (a && b || c)

// Correct:
if ((a && b) || c)

// Wrong:
a + b & c

// Correct:
(a + b) & c

Whitespace

  • Always use a single white space after a keyword.

// Wrong:
if(condition)

// Correct:
if (condition)
  • Use a single white space after a comma.

  • Use a single white space before and after a mathematical or logical operator.

// Wrong:
myFunction(1,2,3);
a= 2+3;

// Correct:
myFunction(1, 2, 3);
a = 2 + 3;
  • You may use additional white space where it enhances readability of the code, but please use sparingly.

MStructuredGrid *mean   = nullptr;
MStructuredGrid *stddev = nullptr;

Switch statements

  • Case labels are in the same column as the switch statement.

  • Every case must have a break statement at the end. If the break is avoided intentionally, indicate so by a comment – unless the next case follows immediately.

switch (myEnum)
{
case Value1:
    doSomething();
    break;
case Value2:
case Value3:
    doSomethingElse();
    // fall through
default:
    defaultHandling();
    break;
}

Type casting

  • Avoid C-style casts where possible.

// Wrong:
char* blockOfMemory = (char* ) malloc(data.size());

// Correct:
char *blockOfMemory = reinterpret_cast<char*>(malloc(data.size()));

Qt specifics

Met.3D heavily builds on Qt.

  • Prefer Qt types to standard library types wherever possible (e.g. use QVector instead of std::vector).

  • Use the Qt foreach statement to iterate over container elements.

QList<MTask*> taskQueue;
foreach(MTask *task, taskQueue)
{
    doSomethingWith(task);
}
  • To avoid compiler warnings for unused parameters in empty (e.g. virtual) functions, use the Q_UNUSED macro.

virtual void onOtherActorCreated(MActor *actor) { Q_UNUSED(actor); }

Logging and console output

Met.3D uses the log4cplus library for logging and console output.

  • Do not use std::cout to print output, use the log4cplus functions instead.

  • Different functions are available for debug, error, info output (and others).

  • Use the globally defined log object mlog for logging output.

// Wrong:
std:cout << "Some debug message." << endl;

// Correct:
LOG4CPLUS_DEBUG(mlog, "Some debug message.");

Comments

  • Write enough comments so that your code can be easily understood by a person who reads the code for the first time (consider being this person and check if you would understand what your code does).

  • Doxygen comments used to document methods in the header files use the format shown in the template header above.

  • Every function of a class (unless very obvious) should be commented in the corresponding header file.

  • Inline comments are placed in the code by using the // indicator. Do not use /*  ... */.

  • Write comments as complete English sentences, starting with a capital letter and ending with a period.

  • Comment should add information, not state the obvious.

// Wrong:

// next I call my function
filterUserComments(comments);

// Correct:

// Users may have left weird comments, so get rid of those.
filterUserComments(comments);
  • Very short comments can be placed at the end of a code line. These do not have to be complete sentences.

k = 0; // number of ensemble members

Compiler warnings

  • Write your code such that as few compiler warnings as possible appear. Ideally, your code should have no warnings at all.