-
Notifications
You must be signed in to change notification settings - Fork 95
CPP Coding Style
Table of contents:
- Tools
- Naming Conventions
- Specific Naming Conventions
- Files
- Include Files and Include Statements
- Statements
- Inheritance
- Variables
- Loops
- Conditionals
- Functions
- Enums
- Miscellaneous
- White Space
- Comments
In order to facilitate the respect of our coding style, developer should respect the style defined in our clang format configuration file: https://github.com/opendr-eu/opendr/blob/master/.clang-format
clang-format
may be used with the Atom text editor by installing the atom-beautify
package (apm install atom-beautify
) and setting clang-format
as the default Beautifier for C and C++ languages.
Note that no warnings are printed and the beautify has to be executed manually or you should enable the apply on save options.
On Ubuntu, clang-format
10.0 can be installed from APT and then you have to install clang-format
Atom package:
sudo apt remove clang-format clang-format-3.8 # if required
sudo apt install clang-format-10.0
sudo ln -s /usr/bin/clang-format-10.0 /usr/bin/clang-format
It may be needed to patch atom beautify with this: https://github.com/Glavin001/atom-beautify/issues/2290
On macOS, simply type:
brew install clang-format
apm install clang-format
... and to set clang-format
into the Atom / Preferences / Packages / Clang Format / Settings / Executable
.
cppcheck
is also very useful to check for both the style and possible programming errors.
The latest version is available from http://cppcheck.sourceforge.net.
On Ubuntu you have to install cppcheck
from sources to get the latest version.
Extract the package and type:
make MATCHCOMPILER=yes FILESDIR=/usr/share/cppcheck HAVE_RULES=yes
sudo make install FILESDIR=/usr/share/cppcheck/
On macOS, simply type:
brew install cppcheck
apm install linter-cppcheck
Unfortunately, the linter-cppcheck
atom package seems to be currently broken and unsupported.
cppcheck
is used in the CI sources tests with the following options:
- Enable Information
- Enable Missing Include
- Enable Performance
- Enable Portability
- Enable Style
- Enable Warning
- Inline Suppressions
Names representing types must be in PascalCase
notation: mixed case starting with upper case.
Line, SavingsAccount
C++ Variable names must be in camelCase
: mixed case starting with lower case.
int line;
SavingsAccount savingsAccount;
private:
int mLineSize;
SavingsAccount mSavingsAccount;
private:
static int cLineSize;
static SavingsAccount cSavingsAccount;
static int gLine;
#CS306 Global constant names (including enum values) must be all uppercase using underscore to separate words.
static const int MAX_ITERATIONS;
enum { RED, GREEN, BLUE };
#CS307 Names representing methods or functions must be written in mixed case starting with lower case.
QString name();
double computeTotalWidth();
template<class T> ...
template<class C, class D> ...
void setTopic(Topic *topic)
// NOT: void setTopic(Topic *value)
// NOT: void setTopic(Topic *aTopic)
// NOT: void setTopic(Topic *t)
void connect(Database *database)
// NOT: void connect(Database *db)
// NOT: void connect (Database *oracleDB)
#CS310 Variables with a large scope should have long names, variables with a small scope can have shorter names.
line.length(); // NOT: line.lineLength();
employee.setName(name);
matrix.setElement(2, 4, value);
#CS313 Methods that return a value should be named after the value they return (without get prefix).
employee.name(); // NOT employee.getName();
matrix.element(2, 4); // NOT matrix.getElement(2, 4);
valueSet->computeAverage();
matrix->computeInverse();
vertex.findNearestVertex();
matrix.findMinElement();
#CS316 The init
prefix should be used where an object or a concept is established and match with a corresponding cleanup
prefix.
printer.initFontSet();
:
printer.cleanupFontSet();
mainWindow, propertiesDialog, widthScale, loginText, leftScrollbar, mainForm, fileMenu, minLabel, exitButton, yesToggle etc.
vector<Point> points;
int values[];
nPoints, nLines
for (int i = 0; i < nTables); ++i) {
:
}
vector<MyClass>::iterator i;
for (i = list.begin(); i != list.end(); ++i) {
Element element = *i;
:
}
bool isSet() const { return mIsSet; }
bool isVisible() const;
bool isFinished() const;
private:
bool mIsFound;
bool mIsOpen;
// There are a few alternatives to the `is` prefix that fit better in some situations. These are the `has`, `can` and `should` prefixes:
bool hasLicense();
bool canEvaluate();
bool shouldSort();
init/cleanup, add/remove, create/destroy, start/stop, insert/delete, increment/decrement, old/new, begin/end, first/last, up/down, min/max, next/previous, old/new, open/close, show/hide, suspend/resume, etc.
bool hasErrors; // NOT: hasNoError
bool isFound; // NOT: isNotFound
bool isRunning() // NOT: isNotRunning()
C++ header files should have the .hpp
extension. C++ source files should have the .cpp
extension.
MyClass.cpp, MyClass.hpp
#CS325 A class should be declared in a header file and defined in a source file where the name of the files match the name of the class.
MyClass.hpp:
class MyClass {
:
Inlining should be used for methods that can be written in one line or so (typically getters and setters), if no additional include is required.
class MyClass {
void setValue(Value value) { mValue = value; }
Value value() const { return mValue; }
For optimization reasons, longer methods can also be inlined, in this case the body of the method must be placed in the header file, just below the class declaration. Remember to avoid early optimization.
#ifndef CLASS_NAME_HPP
#define CLASS_NAME_HPP
:
#endif
#include
statements in a header or a source file should respect the following order, seperated by an empty line:
- the most meaningful header comes first, followed by an empty line; usually we include "MyClass.hpp" at the top of MyClass.cpp text
- toolkit headers come second in alphabetical order
- standard headers come last in alphabetical order
%From MyClass.cpp
#include "MyClass.hpp"
#include "OtherClass1.hpp"
#include "OtherClass2.hpp"
#include <limits>
#include <cassert>
#include "MyOtherClass.hpp" // NO
class MyOtherClass; // YES
#CS333 The parts of a class must be sorted public, protected and private. All sections must be identified explicitly.
class MyClass {
public:
...
protected:
...
private:
...
}
#CS335 Use virtual in front of a derived function declaration if the base class function was declared virtual.
class DerivedClass : public BaseClass {
QString s = "abc";
int x, y, z;
computeCenter(&x, &y, &z);
if (x > z) {
int w = x * z;
:
}
#CS340 Member variables should be initialized in the constructor initialization list provided it doesn't yield code duplication in other constructors.
MyClass::MyClass() : mMySize(10), mMyObject1("obj1"), mMyObject2("obj2") {
% non trivial initialization;
}
#CS341 Place a function's variables in the narrowest scope possible (block, function, class), and initialize variables in the declaration.
int i;
i = f(); // BAD - initialization separate from declaration.
int j = g(); // GOOD - declaration has initialization.
MyVector2 u(0.0, 1.0, 0.0);
MyVector2 v(u); // YES
MyVector2 w = u; // the very same thing as above, but NO
// BAD!
class MyClass {
public:
int numEmployee;
}
// GOOD
class MyClass {
public:
void setNumberOfEmployees();
int numberOfEmployees() const;
private:
int mNumberOfEmployee;
}
#CS345 C++ pointers and references should have their reference symbol next to the name rather than to the type.
float *x, *y, *z; // NOT: float* x, y, z;
int &y; // NOT: int& y;
if (isFinished()) {
:
}
// YES
if (isFinished()) ...
if (!isOpen()) ...
// NO
if (isFinished() == true) ...
if (isOpen() == false) ...
bool isDone = false;
while (!isDone) {
:
}
#CS349 The use of break and continue in loops should only be used if they give higher readability than their structured counterparts.
while (true) {
:
}
if (condition) {
statements;
}
if (condition) {
statements;
} else {
statements;
}
if (condition) {
statements;
} else if (condition) {
statements;
} else {
statements;
}
for (initialization; condition; update) {
statements;
}
while (condition) {
statements;
}
#CS354 Single if
, while
or for
statement must be written without brackets. The statement part should be put on a separate line. In case of nested block keep brackets.
// BAD:
if (condition)
for (initialization; condition; update)
statement;
if (condition) statement;
// GOOD:
if (condition) {
for (initialization; condition; update)
statement;
}
if (condition)
statement;
while (condition)
statement;
for (initialization; condition; update)
statement;
// GOOD
File *fileHandle = open(fileName, "w");
if (!fileHandle) {
:
}
// BAD
if (!(fileHandle = open(fileName, "w"))) {
:
}
#CS356 Write small and focused functions: the body of a function should not exceed one page (no scrolling).
#CS358 When defining a function, parameter order is: inputs, then outputs. If a function returns only one value use the return type.
void computePoints(const Line &line, Point &p1, Point &p2);
Point computePoint(const Line &line1, const Line &line2);
vector<MyClass>::iterator i;
for (i = list.begin(); i != list.end(); ++i) { % NOT i++
Element element = *i;
:
}
enum {
A, // implicitly 0
B, // implicitly 1
C = 12,
D // implicitly 12
}
double total = 0.0; // NOT: double total = 0;
double speed = 3.0e8; // NOT: double speed = 3e8;
double sum = (a + b) * 10.0;
if (p == NULL && fabs(a) == 0.0 && size == 0)
char c = '\0';
A *a = (A*)b; // NO
A *a = static_cast<A*>(b); // YES
A *a = dynamic_cast<A*>(b);
if (a)
doSomethingWithA(a);
- To define mathematical classes, and only if the operators supports a known math syntax
- To inter-operate with streams
- Declare const any method that does not change a variable of its class.
- Declare const any pointer or reference parameter that will not be altered by a function.
- Declare const any variable which value will not change.
double computeTotal(const double v[], int n) const;
const double size = 4.5;
#CS373 Conventional operators should be surrounded by a space character. Commas and semi-colons (in for loops) should be followed by a white space.
a = (b + c) * d; // NOT: a=(b+c)*d
doSomething(a, b, c, d); // NOT: doSomething(a,b,c,d);
for (i = 0; i < 10; ++i) { // NOT: for(i=0;i<10;i++){ ...
Matrix4x4 matrix = new Matrix4x4();
double cosAngle = Math.cos(angle);
double sinAngle = Math.sin(angle);
matrix.setElement(1, 1, cosAngle);
matrix.setElement(1, 2, sinAngle);
matrix.setElement(2, 1, -sinAngle);
matrix.setElement(2, 2, cosAngle);
multiply(matrix);
class MyClass: public BaseClass {
public:
MyClass();
virtual ~MyClass();
void setData(Data *data);
private:
Data *mData;
}