Coding Style (C++)#

This is an overview of the coding conventions we use when writing C++ code for the Open Chemistry projects. The style is based largely on the Qt and KDE styles.

Code formatting is enforced through use of the clang-format tool.

Indentation#

  • 2 spaces are used for indentation

  • Spaces, not tabs!

Line Width#

  • Keep lines of source code to less than 80 characters wide.

Declaring Variables#

  • Declare each variable on a separate line

  • Avoid abbreviations (e.g. “a”, “nmbr”) where possible

  • Single character variable names are fine for counters, temporary variables etc where the purpose is obvious

  • Wait until a variable is needed to declare it, don’t keep unused ones around

// Incorrect
int nmbr, f;

// Correct
int number;
int result;
  • Variables and function names start with a lower case letter, with other words using camel case

  • Abbreviated names should be avoided

  • Acronyms are camel-cased (e.g. CmlFormat, not CMLFormat)

// Incorrect
double Cntr;
std::string rawXML;
char LIST_DELIMITER = '\t';

// Correct
double center;
std::string rawXml;
char listDelimiter = '\t';
  • Class names always start with an upper-case letter

  • Public classes should be placed inside the appropriate namespace

  • Member variables should start with m_

Whitespace#

  • Use blank lines to group statements together where appropriate

  • Only use a single blank line

  • Always use a single space after a keyword and before a curly brace

// Wrong
if(blah){
  explode();
  return 5;
}

// Correct
if (blah) {
  explode();
  return 5;
}
  • For pointers or references, always use a single space between the type and the ‘*’ or ‘&’, but no space between that character and the variable name.

char *x;
const std::string &myString;
const char * const y = "whoah";
  • Surround binary operators with spaces

  • No space after a cast

  • Avoid the use of C-style casts

// Incorrect
char* memoryBlock = (char*) malloc(data.size());
// Correct
char *memoryBlock = reinterpret_cast<char *>(malloc(data.size()));

Braces#

  • The left curly brace normally goes on the same line as the start of the statement

//Incorrect
if (foo)
{
  run();
  break;
}

// Correct
if (foo) {
  run();
  break;
}
  • Exception: if this is class declarations and function implementations. The left brace always goes on the start of a line there

void myFun(const std::string &name)
{
  std::cout << "Supplied name: " << name << std::endl;
}

class Bar
{
public:
  Bar();
};
  • Use curly braces when the body of a conditional contains more than one line, and also if a single statement is complex

// Incorrect
if (!correct) {
  return false;
}

for (int i = 0; i < 42; ++i) {
  var += i;
}

// Correct
if (!correct)
  return false;

for (int i = 0; i < 42; ++i)
  var += i;
  • Exception: Use curly braces if the parent statement does not fit on one line/wraps

// Correct
if (!correct || !isValid
    || !aGoodDay) {
  return false;
}
  • Exception: Use curly braces in any if, then, else blocks where any of the elements cover several lines

// Incorrect
if (!correct)
  return false;
else {
  ++counter;
  return true;
}

// Correct
if (!correct) {
  return false;
}
else {
  ++counter;
  return true;
}

// Incorrect
if (a)
  if (b)
    return true;
  else
    return false;

// Correct
if (a) {
  if (b)
    return true;
  else
    return false;
}
  • Use curly braces when the body is empty.

// Incorrect
while (true);

// Correct
while (true) {}

Parentheses#

  • Parentheses should be used to group expressions, and to make the intent clearer

// Incorrect
if (a && b || c)

// Correct
if ((a && b) || c)

// Incorrect
x = a + b & c;

// Correct
x = (a + b) & c;

Switch Statements#

  • The case labels should be in the same column as the switch

  • Every case must have a break/return statement at the end, or a comment to indicate the omission

  • Exception: Another case follows immediately

switch (myEnum) {
case LINE:
  drawLine();
  break;
case POINT:
case VERTEX:
  drawDot();
// Fall through to default.
default:
  drawDefault();
  break;
}

Line Breaks#

  • Keep lines shorter than 80 characters; insert breaks if necessary

  • Commas go at the end of a broken line

  • Operators go at the beginning of a new line

// Correct
if (veryLongExpression()
    && anotherEvenLongerExpression()
    && justWhenYouThoughtItCouldntGetLonger()) {
  doSomething();
}
Eigen::Vector3d position(currentPosition.x() + offset,
                         currentPosition.y() + offset,
                         0);

Inheritance and the “virtual” Keyword#

  • When reimplementing a virtual method, do not put the “virtual” keyword in the header

Referencing Members#

  • The use of this-> is discouraged. The use of the m_ prefix should make it clear that a member variable is being referenced.

File Naming#

  • All file names should be lower-case.

  • C++ source files should have a .cpp extension.

  • C++ header files should have a .h extension.

Breaking Rules#

  • As with Qt, and others, feel free to break a rule if it makes your code look bad!