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 code in the Met.3D code base that breaks the conventions described here. This is mostly old code, which will be reformatted with time. For new code, please use the conventions described in the following. .. _Qt Coding Style: https://wiki.qt.io/Qt_Coding_Style General file structure ---------------------- Both header (\*.h) and source (\*.cpp) files start with a common header that indicates license and copyright information of the file: .. code-block:: C++ :linenos: /****************************************************************************** ** ** This file is part of Met.3D -- a research software for interactive ** three-dimensional visual analysis of atmospheric data. ** ** Copyright 2016 ... ** ** Met.3D is free software: you can redistribute it and/or modify ** it under the terms of the GNU General Public License as published by ** the Free Software Foundation, either version 3 of the License, or ** (at your option) any later version. ** ** Met.3D is distributed in the hope that it will be useful, ** but WITHOUT ANY WARRANTY; without even the implied warranty of ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ** GNU General Public License for more details. ** ** You should have received a copy of the GNU General Public License ** along with Met.3D. If not, see . ** *******************************************************************************/ Following the header, C++ header files follow the structure: .. code-block:: C++ :linenos: #ifndef MYMET3DCLASS_H #define MYMET3DCLASS_H // standard library imports #include // related third party imports #include // local application imports #include "gxfw/mactor.h" namespace Met3D { /** @brief The class MMyMet3DClass is briefly described in this Doxygen comment. */ class MMyMet3DClass { public: MMyMet3DClass(); ~MMyMet3DClass(); /** This comment documents the following function in Doxygen style. All methods should be briefly described in the C++ header file. Do not repeat the description in the source file. */ void setMyProperty(int someNumber); protected: // protected method and variable definitions ... int myProperty; private: // private method and variable definitions ... }; } // namespace Met3D #endif // MYMET3DCLASS_H Following the header, C++ source files follow the structure: .. code-block:: C++ :linenos: #include "mymet3dclass.h" // standard library imports #include // related third party imports #include // local application imports #include "util/mutil.h" using namespace std; namespace Met3D { /****************************************************************************** *** CONSTRUCTOR / DESTRUCTOR *** *******************************************************************************/ MMyMet3DClass::MMyMet3DClass() : myProperty(42) { // ... do something ... } MMyMet3DClass::~MMyMet3DClass() { // ... do something ... } /****************************************************************************** *** PUBLIC METHODS *** *******************************************************************************/ void MMyMet3DClass::setMyProperty(int someNumber) { myProperty = someNumber; } /****************************************************************************** *** PROTECTED METHODS *** *******************************************************************************/ // ... some definitions ... /****************************************************************************** *** PRIVATE METHODS *** *******************************************************************************/ // ... some definitions ... } // 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. :code:`r`, :code:`rwqrr`, :code:`laksjdiuqk`). * Only use single character names (e.g. :code:`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. .. code-block:: C++ // 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. .. code-block:: C++ // 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. :code:`MTask`) followed by an upper case letter. * Acronyms are camel-cased (e.g. :code:`MHsvColourBar`, not :code:`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. .. code-block:: C++ // 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. .. code-block:: C++ // Wrong: if (condition) { // .. some code .. } else { // .. some code .. } // Correct: if (condition) { // .. some code .. } else { // .. some code .. } Parentheses ----------- * Group expressions by using parentheses. .. code-block:: C++ // 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. .. code-block:: C++ // 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. .. code-block:: C++ // 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. .. code-block:: C++ 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. .. code-block:: C++ switch (myEnum) { case Value1: doSomething(); break; case Value2: case Value3: doSomethingElse(); // fall through default: defaultHandling(); break; } Type casting ------------ * Avoid C-style casts where possible. .. code-block:: C++ // Wrong: char* blockOfMemory = (char* ) malloc(data.size()); // Correct: char *blockOfMemory = reinterpret_cast(malloc(data.size())); Qt specifics ------------ Met.3D heavily builds on Qt. * Prefer Qt types to standard library types wherever possible (e.g. use :code:`QVector` instead of :code:`std::vector`). * Use the C++11 range-based for-loop to iterate over Qt container elements. Do not use the Qt :code:`foreach` statement, as it will be removed in future versions of Qt. .. code-block:: C++ QList taskQueue; for (MTask *task : taskQueue) { doSomethingWith(task); } QList stringList; for (const QString &string : stringList) { doSomethingWith(string); } * To avoid compiler warnings for unused parameters in empty (e.g. virtual) functions, use the :code:`Q_UNUSED` macro. .. code-block:: C++ 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 :code:`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. .. code-block:: C++ // Wrong: std:cout << "Some debug message." << endl; // Correct: LOG4CPLUS_DEBUG(mlog, "Some debug message."); .. _log4cplus: https://sourceforge.net/p/log4cplus/wiki/Home/ 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 :code:`//` indicator. Do not use :code:`/* ... */`. * Write comments as complete English sentences, starting with a capital letter and ending with a period. * Comment should add information, not state the obvious. .. code-block:: C++ // 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. .. code-block:: C++ 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. Naming Conventions ------------------ Please also follow these naming conventions for our cpp code. Properties ~~~~~~~~~~ Properties should always have a ``Prop`` suffix. Also, the user visible name of the property should be sentence cased. .. code-block:: C++ // Wrong: MBoolProperty exampleBool = MBoolProperty("example bool", false); // Correct: MBoolProperty exampleBoolProp = MBoolProperty("Example bool", false);