Coding Style Guidelines¶
Text Formatting¶
Tabulations¶
Use soft tabs with a width of 4 spaces.
Do not use hard tabs.
Do
void myFunction() {
if (something) {
std::cout << "Hello, world!" << std::endl;
}
}
Don’t
// This indentation uses 2 spaces, which is incorrect
// Any other indentation width is also incorrect
void myFunction() {
if (something) {
std::cout << "Hello, world!" << std::endl;
}
}
Language Features¶
Pointers and References¶
Use references over pointers where possible.
Use
std::unique_ptr,std::shared_ptrandstd::weak_ptrover raw pointers where possible.Use
reset(), ornullptroverNULLor0Avoid using
newanddelete
Do
std::unique_ptr<MyClass> myUniquePtr = std::make_unique<MyClass>();
std::shared_ptr<MyClass> mySharedPtr = std::make_shared<MyClass>();
std::weak_ptr<MyClass> myWeakPtr = mySharedPtr;
CStyleResource *cStyleResource = CStyleLibrary_CreateResource();
myUniquePtr.reset();
mySharedPtr.reset();
CStyleLibrary_DestroyResource(cStyleResource);
cStyleResource = nullptr;
Don’t
MyClass *myRawPtr = new MyClass();
MyClass *myRawPtr2 = NULL;
MyClass *myRawPtr3 = 0;
CStyleResource *cStyleResource = CStyleLibrary_CreateResource();
delete myRawPtr;
Reference to this¶
thiscan be used to refer to the current object.You can omit
this->when accessing member variables.
Do
void MyClass::myFunction() {
_myVariable = 42;
this->_myVariable = 42;
}
Positioning of const, & and *¶
conston variables and member variables is always placed before the type.&and*are always placed after the type, sticking to the name of variables and member variables.&and*never stick to function names.
Do
int & myFunction(int &myVariable) {
const int *myPointer = nullptr;
int &myReference = myVariable;
return myReference;
}
Don’t
int& myFunction(int& myVariable) {
int* const myPointer = nullptr;
int& myReference = myVariable;
return myReference;
}
Virtual Methods and Functions¶
Use
virtualto specify that a method can be overridden.Use
overrideto specify that you’ve overridden a virtual function.Use
finalto specify a method cannot be overridden.
Do
class BaseClass {
public:
virtual void myVirtualFunction() = 0;
virtual void myOtherVirtualFunction() const;
};
class DerivedClass : public BaseClass {
public:
void myVirtualFunction() override;
void myOtherVirtualFunction() const override final;
};
Don’t
class BaseClass {
public:
virtual void myVirtualFunction();
virtual void myOtherVirtualFunction() const;
};
class DerivedClass : public BaseClass {
public:
void myVirtualFunction();
void myOtherVirtualFunction() const;
};
Preprocessor Directives¶
Include Guards¶
Use
#pragma oncefor include guards.Do not use
#ifndef,#define,#endiffor include guards.
Do
#pragma once
class TestClass {
public:
// ...
};
Don’t
#ifndef TEST_CLASS_HPP
#define TEST_CLASS_HPP
class TestClass {
public:
// ...
};
#endif
Include Directives¶
Include paths must be absolute to the project root.
Include directives should be grouped
Use quoted paths for internal includes, and angle brackets for external includes.
Use C++ to C header bindings where possible.
Do
// In src/engine or include/engine
#include "bboq/engine/Engine.hpp"
// Outside of src/engine or include/engine (e.g. in src/game/rtype)
#include <bboq/engine/Engine.hpp>
#include <SFML/Graphics.hpp>
#include <iostream>
#include <cstddef>
#include <cstdint>
Don’t
#include "Engine.hpp"
#include "SFML/Graphics.hpp"
#include "iostream"
#include "stddef.h"
#include "stdint.h"
Preprocessor Directives¶
Do not overuse preprocessor directives.
Use
#if defined(...)over#ifdefand#ifndef.Indentation should be consistent with the surrounding code.
Do
#if defined(BBOC_CLIENT) && defined(DEBUG)
#if defined(SOMETHING_SOMETHING)
std::cout << "This is another test" << std::endl;
#endif
std::cout << "Hello, world as a Debug binary!" << std::endl;
#endif
void testFunction() {
#if defined(BBOC_SERVER)
std::cout << "Goodbye, world!" << std::endl;
#endif
}
Don’t
#ifdef BBOC_CLIENT
#ifdef DEBUG
std::cout << "Hello, world as a Debug binary!" << std::endl;
#endif
#endif
void testFunction() {
#ifdef BBOC_SERVER
std::cout << "Goodbye, world!" << std::endl;
#endif
}
Namespaces¶
General Conventions¶
Use
using namespaceonly in scopes where it is necessary, and never in header files.Namespaces follow the
PascalCasenaming convention.
Engine¶
The engine (all files under
/src/engineand/include/engine) uses theBBOCnamespace.
Do
namespace BBOC {
// ...
};
Don’t
namespace engine {
// ...
};
// Don't do this in a header file
using namespace BBOC;
Games¶
Games use their own namespace.
Do
namespace RType {
// ...
};
RType::...
Don’t
namespace game {
// ...
};
namespace BBOC {
// ...
};
Naming Conventions¶
General Naming¶
Use
PascalCasefor class, structure and type alias names.
Do
class MyClassName {
public:
// ...
}
Don’t
class myClass_name {
public:
// ...
}
Function Names¶
Use
camelCasefor function names.
Do
void myFunctionName() {
// ...
}
Don’t
void MyFunctionName() {
// ...
}
void another_function_name() {
// ...
}
Variable Names¶
Use
camelCasefor variable names.
Do
bool thisIsAVariable;
int hello;
std::string myString;
Don’t
bool ThisIsAVariable;
int hello_world;
std::string My_String;
Constants¶
Use
UPPER_CASEfor constants.Use
constexprwhere possible overconst.Never use
#definestatements for constants.
Do
class TestClass {
public:
// `constexpr` can be used for primitive types, including those aliased with `using`
static constexpr int MY_SUPERB_CONSTANT = 42;
// Use `const` otherwise...
static const MyObject MY_INCREDIBLE_OBJECT;
}
// And define your value in the associated .cpp file:
const TestClass::MyObject TestClass::MY_INCREDIBLE_OBJECT = MyObject();
Don’t
#define MY_SUPERB_CONSTANT 42
class TestClass {
public:
static const int MY_SUPERB_CONSTANT = 42;
static const MyObject myIncredibleObject;
}
Enumerations¶
Use
UPPER_CASEfor enumeration values.Declare enumerations with
enum class(C++ style) instead ofenum(C style).Do not use
#definestatements for enumerations or enumeration values.
Do
enum class MyEnum {
FIRST_VALUE,
SECOND_VALUE,
THIRD_VALUE
};
enum class MyValueEnum : std::uint8_t {
FIRST_VALUE = 0,
SECOND_VALUE = 1,
THIRD_VALUE = 2
};
Don’t
enum MyEnum {
FIRST_VALUE,
SECOND_VALUE,
THIRD_VALUE
};
#define FIRST_VALUE 0
#define SECOND_VALUE 1
#define THIRD_VALUE 2
Classes and Structures¶
Member Variables¶
The indentation of
public,protectedandprivatesections must be the same as for the class definition.Use
privateoverprotectedwhenever possible.Member variables must be prefixed with
_, regardless of their visibility.Member variables should be declared at the bottom of the class definition.
Do
class TestClass {
public:
void myFunction();
private:
int _myTestVariable;
bool _myOtherTestVariable;
std::string _myPrivateVariable;
std::vector<int> _myOtherPrivateVariable;
};
Don’t
class TestClass {
protected: // unnecessary here
int myTestVariable;
bool myOtherTestVariable;
std::string MyPrivate_Variable;
std::vector<int> ___myOtherPrivateVariable;
public:
void myFunction();
};