Chaos Project

Featured Projects => Advanced RPG Creator => ARC Reactor Engine => Topic started by: Blizzard on March 10, 2011, 03:25:00 am

Title: Coding Conventions and Good C++ Practice
Post by: Blizzard on March 10, 2011, 03:25:00 am
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, Operators

A 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.

Template: ShowHide
#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.





Spaces

Use proper spaces between operators and operands, method parameters etc.

Examples: ShowHide
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




Parenthesis

Using the right parenthesis at the right place can make things easier to understand. You should use parenthesis when:





Header Includes

Don'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();
};

A.cpp: ShowHide

#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 Setters

While 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.

without inline: ShowHide
Code: Point.h
class Point
{
public:
   Point();
   ~Point();
   
   int getX();
   void setX(int value);
   int getY();
   void setY(int value);
   
protected:
   int x;
   int y;
   
};

Code: Point.cpp
#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;
}

with inline: ShowHide
Code: Point.h
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;
   
};

Code: Point.cpp

#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.



Miscellaneous

Using the right parenthesis at the right place can make things easier to understand. You should use parenthesis when:






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.
Title: Re: Coding Conventions and Good C++ Practice
Post by: Blizzard on March 10, 2011, 02:17:24 pm
I have added Inline Implementation of Trivial Getters and Setters. I will update the code in SVN now to match this convention.

EDIT: I added this to variables, etc.:



EDIT: I edit this:



EDIT: Added one more thing to misc:

Title: Re: Coding Conventions and Good C++ Practice
Post by: Blizzard on March 13, 2011, 11:25:43 am
Guys, you are not keeping the coding convention and you are not committing stable builds.

Also, Ryex, it's visible, not visable. :P

And you don't really need to add comments that say "forward declaration of blablabla" or "public variables". Those things are more or less obvious. The documentation itself and self-documenting code is pretty much all that is needed, except in some very abstract cases where comment really should be added or if you want to mark specific blocks of code.

EDIT: Also, please end your sentences with fullstops.

EDIT: Don't get me wrong. I'm not angry at you. I'm merely asking you to pay attention in the future and fix your coding so far.

EDIT: I updated the template so we use a rb_ prefix for functions that are interfaced with Ruby.