This is an old revision of the document!
Table of Contents
Coding Style
Braces
Naming
Item | Example | Comment |
---|---|---|
type (class/struct) | SomeExample | |
variable | someExample | |
member variable | m_someExample | |
global variables | gSomeExample | should be avoided |
function | someExample() | |
member function | someExample() | |
getter function | name() | not getName(), Qt convention |
setter function | setName() | |
namespace | SomeExample | |
template parameter | SomeExample |
Never use abbreviations in names, having long names is not an issue: all IDEs have an auto-completion feature.
// Bad void getNbApples() { int avgFuncSizePerAlloc = 42; //... } // Good void getAppleCount() { int averageFunctionSizePerAllocation = 42; //... }
Code files
Code separation
Generally speaking, each class/struct should have its declaration in one file (header) and its definition in another file (source file). If a class/struct is very small then it can be contained in a header, for example if it only contains variables and no functions. Qt specific: note that QObject/QWidget-based classes have to have their own header file in order to the MOC (Qt's meta compiler) to find them.
Naming
Source files should have the .cpp extension (common practice) and header files the .hpp extension. Note here that the .h extension may be more common, but I personally think that the .hpp extension makes more sense since C++ headers are not generally compatible with the C language.
Header guards
Header guards are a C++-specific feature kept for historical reasons. The official way of using them is to put all the header code between #defines:
#ifndef MY_HEADER_FILE_H #define MY_HEADER_FILE_H //... #endif // MY_HEADER_FILE_H
However, in practice I find this to be dangerous and I have encountered some particularly serious bugs using this method. Indeed, if you happen to copy/paste a header file you will need to remember having to change the header guard #define name. If you do not do this and if you include both header files, only the first one will be effectively included.
Another way to shoot yourself in the foot using header guards is the use of a namespace. Since preprocessor instructions cannot use them you will get into trouble if a header file within a namespace has the same name as another header file outside of it.
For these reasons, I recommend instead the use of the non-standard feature called “pragma once”:
#pragma once //...
This feature in implemented in all known compilers and is both easier to use and foolproof. It has not been accepted into the C++ standard because of some particular cases, like having source files on multiple “remote mounts”: https://stackoverflow.com/questions/23696115/is-pragma-once-part-of-the-c11-standard.
Examples
#include <string> #include <memory> // An entity semantic class class MyExampleClass final { public: // This constructor is explicit to prevent something like this: MyExampleClass test = "some text"; explicit MyExampleClass(const std::string &myString): m_myVar{52}, m_myString{myString} { } // Entity semantic: always forbid copy & assignment MyExampleClass(const MyExampleClass &) = delete; MyExampleClass &operator=(const MyExampleClass &) = delete; private: // Variables are always at the end, because they represent an implementation detail int m_myVar{42}; std::string m_myString{"value"}; }; // A value semantic class class MyVector final // Always final: a value semantic class should *never* be inherited from { public: // We want to use the default implementation (wich is faster than anything we can do) MyVector() = default; MyVector(const MyVector &other): m_x(other.m_x), m_y(other.m_y) { } MyVector &operator=(MyVector other) { std::swap(m_x, other.m_x); std::swap(m_y, other.m_y); return *this; } private: // m_x and m_y are initialized with the default value for the type int: 0 // unless the initializer list in a constructor decides otherwise int m_x{}; int m_y{}; }; void test() { // I use scopes "{}" here to limit where my variables live and are accessible { // Allocation on the stack (fast) MyExampleClass myExampleClass{"some text"}; // myExampleClass is destroyed here } { // Allocation on the heap (slower, allows polymorphism) std::unique_ptr<MyExampleClass> myExampleClass{std::make_unique<MyExampleClass>("some text")}; // Or (with auto) auto myExampleClass{std::make_unique<MyExampleClass>("some text")}; // myExampleClass is destroyed here (thanks to the smart pointer) } }