-
Notifications
You must be signed in to change notification settings - Fork 13
Programming Style Guide
This is a very general overview and subject to change. If you have questions, contact .
This is C++ not C so you will probably be writing or modifying classes. If you know a Class would never have any methods or be subject to inheritance a struct is fine. Typedefs are frowned upon unless it aids in portability.
It's not the 90s anymore and we prefer it that way. If there is a C++11 semantic that you want to use, feel free so long as it doesn't screw up Visual Studio 2015 or GCC (min. 5.0) support.
The only exception to this is with OpenGL function calls that can accept NULL. In that case we prefer to pass 0 rather than NULL due to some platforms that enjoy throwing warnings.
Try to avoid committing any code that produces warnings to the master branch. If a warning occurs during build please fix it; it's usually trivial and helps keep the build stable.
Please prefix all virtual functions with V
class IFoo
{
public:
virtual void VTest() = 0;
};
Use trailing braces when defining blocks.
Bad:
class Foo{
};
Good:
class Foo
{
};
Bad:
if (x > 0){
}
Good:
if (x > 0)
{
}
Bad:
if (x < 0)
{
//Single Line if
}
Good:
if (x < 0)
//Single Line if
An exception to this is is if you have an if/else where only one could be single line. Use blocks for both in that case.
Bad:
if (x > 0)
//Single Line If
else
{
//Multi Line Else
}
Good:
if (x > 0)
{
//Single Line If
}
else
{
//Multi Line Else
}
class MyClass;
void MyFunction();
class MyClass
{
int myMember;
};
void MyMethod(int myParam);
#define MY_PI 3.14159
enum MyEnum
{
FIRST_VALUE,
SECOND_VALUE
};
enum class MyEnumClass: char
{
high = 'h',
low = 'l'
};
Bad:
//This adds x to y
int Add(int x, int y)
{
return x + y;
}
- If you are writing documentation that is a different story
Good:
//If you register a permission with a name that already exists, you will overwrite the existing permission
void RegisterPermission(const char* name, int id)
{
//Code
}
- Exception for headers with no source file, i.e. interfaces.
We really don't want to have to go through the daunting task back tracking through old code to document it. If you're unfamiliar with Doxygen
##Doxygen Examples *Class
/**
\class ClassName
\ingroup RepoName(i.e. HatchitCore)
\brief A brief description about the class
A more detailed description about the class, and what its purposes
are
**/
class ClassName {};
*Function
/**
\fn bool ClassName::Function() const;
\brief Brief description of function
More detailed description about function, including what it may return
depending on what conditions.
**/
bool ClassName::Function() const { return true; }
Bad:
// Comment
Good:
//Comment
Bad:
/* Multi
Line
Comment
*/
- This doesn't apply to documentation stubs
Good:
/*
Multi
Line
Comment
*/
Bad:
/*
Multi
Line
Comment
*/
Bad:
/*Multi
*Line
*Comment
*/
- This doesn't apply to copyright notices or documentation stubs
- Use .h for headers, .cpp for source files, and .inl for inline source files
- Header and Source names should match or at least contain their class name
- Use multiple Source files where appropriate (MyClass.hpp, MyClass.cpp, MyClassWindows.cpp, MyClassLinux.cpp)
- Source files go in
src/
and Headers go ininclude/
and Inline source files go insrc/inline
- Whenever possible, prefer forward declarations instead of including the header file.
- For typedefs and using statements, prefer including the header file over forcing a forward declaration.
Bad:
//foo.h
struct foo {};
//bar.h
using bar = foo;
//baz.h
struct foo;
using bar = foo;
struct baz { bar b; };
Good:
//foo.h
struct foo {};
//bar.h
using bar = foo;
//baz.h
#include <bar.h>
struct baz { bar b; };
- Include all headers that your file needs to function properly. Do not rely on other headers that also include those dependencies.
Bad:
//foo.h
struct foo {};
//bar.h
#include <foo.h>
struct bar { foo f; };
//baz.h
#include <bar.h>
struct baz { foo f; bar b; };
Good:
//foo.h
struct foo {};
//bar.h
#include <foo.h>
struct bar { foo f; };
//baz.h
#include <foo.h>
#include <bar.h>
struct baz { foo f; bar b; };
#pragma once
/*
Copyright notice if applicable
*/
//Pre-Include Defines
//System level includes
//Project level includes
/*
Any important info about MyClass
OR
Info for documentation engine (cldoc / doxygen / etc)
*/
class MyClass
{
friend class MyFriend;
public:
//Static Methods
//Static Variables
MyClass();
//Public Methods
//Public Variables
virtual ~MyClass();
protected:
//Static Methods
//Static Variables
//Protected Methods
//Protected Variables
private:
//Static Methods
//Static Variables
//Private Methods
//Private Variables
};
Notes:
- Do not use an #ifdef header guard
//Includes
//ALL Static Methods
//ALL Static Variables
MyClass::MyClass()
{
}
//Public Methods
MyClass::~MyClass()
{
}
/*
Make a comment that you're now writing protected methods
*/
//Protected Methods
/*
Make a comment that you're now writing private methods
*/
//Private Methods
All .h and .cpp files should start with a license notification
#Functions
##Function declarations should never be more than 80 characters wide
- new-line on every variable if you cannot fit the signature on one line.
//Bad
int MyFunction(int a, int b, int c, int d, int e, int f, int g, int h, int i, int j ...);
//Also bad
int MyOtherFunction(int a, int b, int c, int d,
int e, int f, int g, int h, int i, int j ...);
//Good
int MyGoodFunction(
int a,
int b,
int c);
- If you don't want to be passed a nullptr, use references over passing pointers to objects.
- Expect non-const references passed into functions to possibly be modified.
#Classes / Structs
- RAII is important! Make sure we're initializing our members to default or given values.
//Bad
Foo::Foo(int a, float b, char c)
{
m_a = a;
m_b = b;
m_c = c;
}
//Good
Bar::Bar(int a, float b, char c) :
m_a(a),
m_b(b),
m_c(c)
{}
#Enums
//Bad
enum FooEnum
{
ENUM_VALUE_A;
};
//Good
enum class BarEnum
{
enumValueB;
};
class Foo
{
enum class FooType
{
//Enums
};
//Code that uses enum
};
- If an enum is used primarily by multiple files, place definition inside separate header file.
//MyEnum.h
enum class MyEnum
{
//Values
};
//Foo.cpp
#include <Foo.h>
#include<MyEnum.h>
void Foo::DoSomething(MyEnum e)
{
//Do something
}
//Bar.cpp
#include<Bar.h>
#include<MyEnum.h>
void Bar::DoSomethingElse(MyEnum e)
{
//Do something else
}
#Preprocessor
- Indent between the # key and the actual statement
//Bad
#if DEBUG
#if SHOULD_PRINT
print();
#endif
#endif
//Good
#if DEBUG
# if SHOULD_PRINT
print();
# endif
#endif