I will list all coding conventions here to make coding simpler and easier to understand between all of us who will script. You wouldn't believe how much it can improve coding, save time and make everything just easier if the coding is consistent.
Classes, Variables, Methods, OperatorsA proper convention for classes, variables, methods and operators can make it much easier to read the code of others as you instantly know their purpose on sight.
#ifndef ZER0_CLASS_NAME_H // careful, the 0 in ZER0 is a zero, not the letter O
#define ZER0_CLASS_NAME_H
#include <someSystemHeader.h>
#include <someOtherSystemHeader>
#include <library/someName.h> // e.g. for april & friends
#include "RGSS/headerRgssHeader.h"
#include "headerWithinZer0.h"
#define CONSTANT (0)
namespace zer0
{
// forward declarations
class X;
class Y;
// contains the Ruby class
static VALUE rb_ClassName;
class zer0export ClassName : public PossibleInheritance
{
public:
// public instance variables
int PublicVariable;
static int StaticVariable;
// public constructors and destructors
ClassName();
ClassName(int a);
~ClassName();
// public inline getters and inline setters
int getPrivateVariable() { return this->privateVariable; }
void setPrivateVariable(int value) { this->privateVariable = value; }
// public getters and setters
int getA();
void setA();
// public operators
ClassName operator+(const ClassName& operator) const
ClassName operator+=(const ClassName& operator)
bool operator==(const ClassName& operator) const
// public methods
void descriptiveMethodName(int parameter, float anotherParameter);
static void staticMethod();
static VALUE rb_rubyInterfaceMethod(VALUE self);
protected:
// protected instance variables
int protectedVariable;
// protected inline getters and setters
int _getProtectedVariable() { return this->protectedVariable; }
void _setProtectedVariable(int value) { this->protectedVariable = value; }
// protected getters and setters
int _getB();
void _setB(int value);
// protected methods
void _protectedMethod();
private:
// private instance variables
int privateVariable;
int c;
// private inline getters and setters
int _getC() { return this->c; }
void _setC(int value) { this->c = value; }
// private getters and setters
int _getD();
void _setD(int value);
// private methods
void _protectedMethod();
};
}
#endif
Don't be confused about "zer0export". This only ensures that the class is visible outside of the DLL. When you inherit a class, you have to add "public" before the name of the superclass. Honestly, I don't know exactly why, but you have to do it.
- Header Guards are always named like ZER0_CLASS_NAME_H.
- Sort header includes by type; first external library headers, then internal library headers, the internal project headers. Sort each type alphabetically.
- Sort the declaration by access; first public, then protected and then private.
- Sort members by type; first instance variables, then static variables, then constructors, then inline getters and setters, then normal getters and setters, then operators, then methods, then static methods.
- Always first put the getter, then the setter. The parameter name in the setter is always "value".
- Both destructive and non-destructive operators should return an instance of the given class. If the operator is destructive, the operator should return the calling class.
- Avoid operators other than public.
- In method calls use "const TYPE&" and "const TYPE" to explicitly disallow the changing of that parameter during the execution of that method. Using "TYPE&" is better performance-wise when working with classes because it does not create a new class but uses the actual classes passed on to the method. Be aware that you can't use "const TYPE&" or "TYPE&" in some situations.
- Add "const" at the end of a method definition is the method is not allows to modify this instance of a class.
- When declaring variables of the same type, declare each in a new line. Do not declare more than one variable of the same type in one line.
SpacesUse proper spaces between operators and operands, method parameters etc.
a = b *c+1; // incorrect
a = b * c + 1; // correct
if (a&&b||c) // incorrect
if (a && b || c) // correct
void method_1(int a,int b,int c) # incorrect
int method_1(int a, int b, int c) # correct
ParenthesisUsing the right parenthesis at the right place can make things easier to understand. You should use parenthesis when:
- having a return value that is a composite: return (a * b);
- using a ternary branching operator: a = (b ? c : d);
- having multiple conditions in a ternary branching operator (required since it won't work otherwise): a = ((b && c < 4) ? d : e);
- (optional) explicit marking of separated code parts in a line: new_position = current_position + (moving_speed * distance) * direction;
Header IncludesDon't include headers in headers except if you must. This reduces recompilation time when you change something in a header because headers are not connected then. Adding headers in source files is fine and you can add as many as you need.
If you are using pointers or references to a class, but never the actual class in a header, then you can use so-called forward declarations of those classes to avoid the include of its header. Basically you are telling the header "this class surely exists somewhere, don't worry about where".
class B
{
public:
int c = 0;
};
class B; // forward declaration of class B
class A
{
public:
B* aPointer;
A();
~A();
};
#include "A.h"
#include "B.h" // notice how here is is necessary to include B's header
A::A()
{
this->aPointer = new B();
}
A::~A()
{
delete this->aPointer;
}
Inline Implementation of Trivial Getters and SettersWhile in classic C, implementing a function in a header will cause linking problems because of multiple implementations, in C++ this can be a useful thing if used with classes. We will implement trivial getters and setters for our classes as inline members. Do not confuse this concept with inline implementations that explicitly use the keyword inline (even though they technically do the same thing). This will result in a bigger executable (slightly), but it will also increase speed. Here is an example of a Point class without and with inlined trvial getters and setters.
class Point
{
public:
Point();
~Point();
int getX();
void setX(int value);
int getY();
void setY(int value);
protected:
int x;
int y;
};
#include "Point.h"
Point::Point() : x(0), y(0)
{
}
Point::~Point()
{
}
int Point::getX()
{
return this->x;
}
void Point::setX(int value)
{
this->x = value;
}
int Point::getY()
{
return this->y;
}
void Point::setY(int value)
{
this->y = value;
}
class Point
{
public:
Point();
~Point();
int getX() { return this->x; }
void setX(int value) { this->x = value; }
int getY() { return this->y; }
void setY(int value) { this->y = value; }
protected:
int x;
int y;
};
#include "Point.h"
Point::Point() : x(0), y(0)
{
}
Point::~Point()
{
}
We will use inline methods
ONLY for trivial getters and setters. Trivial means that it either gets or sets the value directly. No other kind is allowed.
MiscellaneousUsing the right parenthesis at the right place can make things easier to understand. You should use parenthesis when:
- Braces go always into a new line and in that line there is nothing but the braces.
- ALWAYS use "this->" when working with members. Syntax coloring allows you instantly see which variable is a member and which is not.
- Use strict camel case. CamelCaseLooksLikeThis or somethingLikeThis. Even if you use acronyms like GUI and ID, use proper CamelCaseForTheId or theGuiPartOfTheName.
- Use explicit typing of literals. If a variable is a float, don't use "float a = 0;", use instead "float a = 0.0f";
- Use hstr for all your string needs. Always use chstr if you use it as a parameter in methods. chstr is a typedef of "const hstr&".
- Before you commit anything, try to build the project first! It's frustrating to update and then realize it doesn't work.
I will add more conventions as I notice people deviating from things.
If you are unsure into which category something belongs, ask.
If you have suggestions for more conventions, post them.
If you feel that a convention is pointless, post and I will argument the convention more detailed so that you understand its purpose.
If you have any problem understanding the code examples I have given or even if the slightest piece of code is unclear, please post. C++ is a very complex language and it is better if you know what's going on.