MemoryLeakIndicator
Lade ...
Suche ...
Keine Treffer
C++ Programmierrichtlinien dieses Projekts

Einleitung

Um eine gemeinsame Entwicklung in C++ zu erleichtern, ist es sinnvoll, wenn Programmierrichtlinien eingehalten werden. Hier sind die wichtigsten Vorgaben für dieses C++-Projekt aufgeführt.

Bezeichner

Für die einzelnen Typen von Bezeichnern gelten einheitliche Regeln.
Grundsätzlich soll für alle Bezeichner die englischer Sprache genutzt werden.

Dateinamen

In der Regel soll jede Klasse in einer Header-Datei deklariert und in einer Quelltext-Datei definiert werden (ausnahmen sind Template-Klassen, Inline-Methoden und Structs). Beide Dateien bekommen die Klassenbezeichnung als Namen.
Sollten mehrere Klassen in einer Header-Datei deklariert und in einer Quelltext-Datei definiert werden, sollte ein aussagekräftiger Modulname für die Dateien gewählt werden.

C++ Dateiextensions

C++ Header-Dateien und globale Typ-Dateien erhalten die Extension .h.
C++ Quelltext-Dateien erhalten die Extension .cpp.

Klassen-Namen

Klassen-Namen werden grundsätzlich am Anfang mit einem Großbuchstaben eingeleitet.
Um eine Zuordnung zu einem Projekt bzw. zu einer Bibliothek zu signalisieren, können maximal 3 Buchstaben als Kürzel genutzt werden. Davon muss der erste ein Groß- und die weiteren beiden Kleinbuchstaben sein. Die folgende Klassenbezeichnung fängt wieder mit einem Großbuchstaben an. Der Name sollte so gewählt werden, dass der Job der Klasse klar wird. Wenn es sich um eine Bezeichnung aus mehreren Wörtern handelt, sind diese einzeln entsprechend der CamelCase-Notation mit anführenden Großbuchstaben zu schreiben ( z.B. 'GloBaseMaker').
Template-Klassen bekommen vor ihren Namen, nach dem Projekt- bzw. Bibliothek-Kürzel ein 'T' eingefügt (z.B. 'GloTOndemandSet').
Alternativ kann eine Zuordnung zu einem Projekt bzw. zu einer Bibliothek über einen Namensraum (namespace) realisiert werden. Für die Bezeichnung des Namensraums sollten maximal 3 Kleinbuchstaben als Kürzel genutzt werden ( z.B. 'glo::BaseMaker'). Die Wiederholung eines Projektkürzels vor dem Klassen-Namen sollte dann aber vermieden werden.

Attribut-Bezeichnung in Klassen

Die Attribute von Klassen werden grundsätzlich mit einem 'm_' (steht für Member) eingeleitet. Es folgt dann eine umstrittene und nicht ganz durchzuhaltende Kennzeichnung nach der ungarischen Notation gefolgt von einem aussagekräftigen Namen, welcher mit einem Großbuchstaben anfängt (z.B. 'm_sApplicationName' für einen String).

Zu beachten
Statische Attribute werden nicht gesondert gekennzeichnet.

Methoden-Bezeichnung in Klassen

Die Methoden von Klassen werden grundsätzlich mit einem Kleinbuchstaben eingeleitet. Es sollte in der Regel ein Verb benutzt werden, welches die Dienstleistung der Methode beschreibt (z.B. 'loadIconPath'. Wenn Zustände einer Klasse abgefragt werden sollen, hat sich bewährt, die Methodenbezeichnung mit einem 'is' oder 'has' zu beginnen (z.B. 'isStored' oder 'hasConnection'

Zu beachten
Statische Methoden werden nicht gesondert gekennzeichnet.

Globale Variablen

Globale Variablen werden grundsätzlich mit einem 'g_' (steht für global) eingeleitet. Es folgt dann eine umstrittene und nicht ganz durchzuhaltende Kennzeichnung nach der ungarischen Notation gefolgt von einem aussagekräftigen Namen, welcher mit einem Großbuchstaben anfängt (z.B. 'g_sGloVersion' für einen String).

Lokale Variablen in Funktionen und Methoden

Lokale Variablen werden grundsätzlich mit einem 't_' (steht für temporär) eingeleitet. Es folgt dann eine umstrittene und nicht ganz durchzuhaltende Kennzeichnung nach der ungarischen Notation gefolgt von einem aussagekräftigen Namen, welcher mit einem Großbuchstaben anfängt (z.B. 't_iErr' für eine lokale Int-Variable).

Parameter-Bezeichnung

Parameter werden in der Regel mit einer umstrittenen und nicht ganz durchzuhaltende Kennzeichnung nach der ungarischen Notation eingeleitet, gefolgt von einem aussagekräftigen Namen, welcher mit einem Großbuchstaben anfängt (z.B. 'eLockMode' für einen Enum-Wert).

Dateien

Um die Suche nach Inhalten zu vereinfachen, sind einige Datei-Typen vorgegeben bzw. vorgeschlagen.

Klassen

Wie schon unter Dateinamen erwähnt. In der Regel soll jede Klasse in einer Header-Datei deklariert und in einer Quelltext-Datei definiert werden (ausnahmen sind Template-Klassen, Inline-Methoden und Structs). Beide Dateien bekommen die Klassenbezeichnung als Namen.
Sollten mehrere Klassen in einer Header-Datei deklariert und in einer Quelltext-Datei definiert werden, sollte ein aussagekräftiger Modulname gewählt werden.

Siehe auch
Dateinamen und C++ Dateiextensions C++ "Dateiextensions"

Globale Projekttypen

Die globalen Konstanten, Enumerationen und Strukturen werden in einer Header-Datei untergebracht. Der Name dieser Datei sollte das Projekt- bzw. Bibliothekskürzel mit einem folgenden 'Types' sein ( z.B. 'GloTypes').
Wenn Konstanten, Enumerationen und Strukturen nur eine Klasse betreffen, ist immer abzuwägen, ob diese nicht in die jeweilige Klassen gehören.

Globale Fehlerkodes

Für ein Projekt globale Fehlerkodes werden in einer Header-Datei untergebracht. Der Name dieser Datei sollte das Projekt- bzw. Bibliothekskürzel mit einem folgenden 'Errors' sein ( z.B. 'GloErrors').

ToDo-Liste

Eine ToListe 'ToDo.txt' kommt in das jeweilige C++ Projektverzeichnis. In dieser ToDo-Liste werden nach Manier eines Scrum-Backlogs einzelne Anforderungen und noch zu erledigende Dinge priorisiert aufgelistet.

Formattierung

Um das Erkennen von Inhalten zu vereinfachen, sind einige Formatierungen vorgegeben bzw. vorgeschlagen.

UTF8

Jede Textdatei mit Sonderzeichen muss im UTF8-Format gespeichert sein, damit die Sonderzeichen einheitlich behandelt werden.

Einrückungen

Jeder logische Abschnitt im Quelltext sollte eingerückt sein. Einrückungen erfolgen in Schritten von 2 Zeichen. Diese Einrückung soll nicht als Tabulatorzeichen definiert sein.

Geschweifte Klammern

Die Zeichen '{' und '}' stehen immer alleine in einer Zeile. Klammerpaare stehen immer in einer Spalte. Es wird empfohlen, auch einzeilige Anweisungen in '{' und '}' einzuklammern. Beispiel:

int foo::bar( int iValue )
{
int t_iErr = 0;
if ( iValue )
{
t_iErr = this->doSomething( iValue );
}
return t_iErr;
}

Gruppierung

Um die Übersichtlichkeit zu unterstützen, werden logische Einheiten durch Kommentare und Unterbrechungen mit Linien eingeteilt. Beispiel:

...
protected:
//============== Attributes
//-------------------------------------------------------------------------
/*!
\if english
Objectpointer.
\endif
\if german
Zeiger auf Objekt.
\endif
*/
T * m_pT;
//-------------------------------------------------------------------------
/*!
\if english
The reference count.
\endif
\if german
Der Referenzzähler.
\endif
*/
EuSharedPtrRefCount * m_pRefCount;
//-------------------------------------------------------------------------
public:
//============= Constructors, destructor
//-------------------------------------------------------------------------
/*!
\if english
Default constructor can take object.
\param[in] pT Pointer doe object (optional).
\endif
\if german
Standard-Konstruktor kann Objekt übernehmen.
\param[in] pT Zeiger auf Objekt (optional)
\endif
*/
EuSharedPtr(T * pT = NULL);
//-------------------------------------------------------------------------
...

Zeilenlänge

Die Zeilenlänge sollte 80 Zeichen nicht überschreiten. Es gibt Fälle, wo dieses nicht eingehalten werden kann.
Empfehlungen für Zeilenumbrüche, wenn die Zeilenlänge überschritten wird.

  • Parameterübergabe nach einem Komma. Wenn schon, dann am besten alle Parameter in eine Spalte:
    int foo::bar( int iParamName1,
    int iParamName2,
    int iParamName3,
    int iParamName4,
    int iParamName5,
    int iParamName6 )
  • Bei arithmetischen Ausdrücken vor einem Operator:
    int iResult = ( ( iParamName1 + iParamName2 + iParamName3 + iParamName4 )
    iParamName5 ) - iParamName6;
  • Bei einer umfangreichen if-Anweisung bzw. while- und do-while-Schleifen:
    if ( ( iParamName1 && iParamName2 )
    || ( iParamName3 && iParamName4 )
    || ( iParamName5 && iParamName6 ) )
    {
    ...
    }

Variablen Deklaration

Einzelne logisch zusammenhängende Deklarationen und Zuweisungen sollten in der selben Spalte stehen.

int t_iMyValue1,
t_iMySecondValue;
MyClass * t_pMyClass = 0;
t_iMyValue1 = 0;
t_iMySecondValue = 0;
t_pMyClass = new MyClass();

Kommentare

Kommentare und Dokumentationen sind notwendig, um den Quelltext verständlich zu halten.
Kommentare im Quelltext sollten in englischer Sprache verfasst sein bzw. bei Gelegenheit übersetzt werden. Je nach Bedarf können Block- oder Zeilenkommentare genutzt werden.
Die Dokumentation soll in mehreren Sprachen vorhanden sein und den Vorgaben von doxygen genügen.

Siehe auch
Dokumentation mit doxygen.

Dokumentation mit doxygen

Die Dokumentation der C++ Projekte wird mittels doxygen realisiert. Hier wird nicht doxygen als solches beschrieben, sondern wie und wo es angewendet wird.
Wenn es eine sprachspezifische Dokumentation geben soll, wird der jeweilige Dokumentationstexte zwischen '\if german' (für deutsch) und '\endif' eingefasst. Für die englische Sprache wäre das z.B. '\if english' und '\endif'. Das soll ermöglichen, dass jeder Programmierer und jede Programmiererin unabhängig davon welche Sprache(n) beherrscht werden, die jeweiligen OpenSource-Produkte nutzen bzw. am Projekt mitarbeiten können.

Siehe auch
http://www.doxygen.org

Header-Datei

Jede Header-Datei bekommt nach dem Include-Blocker einen Hinweis auf die Lizenz. Eine kurze Beschreibung kann mehrsprachig sein; der Lizenztext ist grundsätzlich englisch.

Beispiel für Klasse 'GloLocalThread'.

#ifndef INC_GLOLOCALTHREAD_H
#define INC_GLOLOCALTHREAD_H
//-----------------------------------------------------------------------------
/*!
\file GloLocalThread.h
\brief
\if english
Header for GloLocalThread
\endif
\if german
Header für GloLocalThread
\endif
\author Helmut Jakoby
\copyright © 2020 Helmut Jakoby
<!-- @@TermsOfLicense BEGIN -->
<b>Terms of License</b>
This file is part of the GlobalObjects module.
GlobalObjects is free software:
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE.
<b>GNU Affero General Public License Usage</b><br>
You can redistribute it and/or modify it under the terms of the GNU Affero
General Public License as published by the Free Software Foundation; either
version 3 of the License, or (at your option) any later version. Please review
the following information to ensure the GNU Affero General Public License
requirements will be met: https://www.gnu.org/licenses/agpl-3.0.en.html .
<!-- @@TermsOfLicense END -->*/
//-----------------------------------------------------------------------------

Der Datei- und Klassenname, der Autorenname und der copyright-Eintrag sowie der Projekt- bzw. Modulname werden angepasst.

Klassen

Nach den ggf. nötigen Forward-Deklarationen und Includes direkt über der Klassen-Deklaration wird die Klasse beschrieben.

Beispiel für Template-Klasse 'GloTOndemandSet':

...
#include "GloBasePersistent.h"
//-----------------------------------------------------------------------------
/*! \brief
\if english
A type-safe set of references to persistent objects in the database (intended
as an attribute for persistent objects).
Unlike a GloTPointerSet (where the referenced objects are 'loaded'), the
GloTOndemandSet is a set of references to persistent objects using the object
ID. This means that the objects are not loaded from the database with the
referencing object, but can be reloaded if required.
It is always useful when an object references large objects that do not
necessarily have to be available in memory.
\endif
\if german
Ein typsicherer Set von Referenzen auf persistente Objekte in der Datenbank
(gedacht als Attribut für persistente Objekte).
Im Gegensatz zu einem GloTPointerSet (bei dem die referenzierten Objekte
'mitgeladen' werden), ist der GloTOndemandSet ein Set von Referenzen über
die Objekt-ID auf persistente Objekt. Es werden die Objekte also nicht mit
dem referenzierenden Objekt aus der Datenbank geladen, sondern können bei
Bedarf nachgeladen werden
Sinnvoller Einsatz ist immer dann gegeben, wenn ein Objekt große Objekte
referenziert, die nicht im jeden Fall im Speicher verfügbare sein müssen.
\endif
\copyright © 2020 Helmut Jakoby
\author Helmut Jakoby
*/
template < class T > class GloTOndemandSet : public GloOndemandSet
{
...

Attribute

Der Beschreibungstext für Attribute wird direkt vor diesem wie im Beispiel dargestellt beschrieben.

Beispiel für ein Attribut 'GloObjID m_RefObjID':

...
//============== Attribute
//-------------------------------------------------------------------------
/*!
\if english
The reference to a persistent object as object ID.
\endif
\if german
Die Referenz auf ein persistentes Objekt als Objekt-ID.
\endif
*/
GloObjID m_RefObjID;
//-------------------------------------------------------------------------
...

Aufzählungen (enums)

Der Beschreibungstext für Aufzählungen wird wie im Beispiel dargestellt beschrieben.

Beispiel 1 für eine Enum 'EnWatchStyle':

...
//============== Enums
//---------------------------------------------------------------------
/*!
\if english
What is being observed, an AllSet or an object?
\endif
\if german
Was wird beobachtet, ein AllSet oder ein Objekt?
\endif
*/
enum EnWatchStyle
{
eUNDEF = 0, /*!<
\if english
Undefined.
\endif
\if german
Undefiniert
\endif
*/
eALLSET, /*!<
\if english
An AllSet will be observed
\endif
\if german
Es wird ein AllSet beobachtet
\endif
*/
eOBJECT /*!<
\if english
An object will be observed
\endif
\if german
Es wird ein Objekt beobachtet
\endif
*/
};
...


Beispiel 2 für eine Enum 'EnOpenClose':

...
//============== Enums
//-------------------------------------------------------------------------
/*!
\if english
The thread can open or close a database.
\endif
\if german
Der Thread kann eine Datenbank öffnen oder schliessen.
\endif
*/
enum EnOpenClose
{
/*!
\if english
The database will be opened.
\endif
\if german
Die Datenbank wird geöffnet.
\endif
*/
eOpen,
/*!
\if english
The database will be closed.
\endif
\if german
Die Datenbank wird geschlossen.
\endif
*/
eClose
};
...

Funktionen und Methoden

Der Beschreibungstext für Funktionen bzw. Methoden wird direkt vor dieser wie im Beispiel dargestellt beschrieben.

Beispiel für eine Methode 'insert(...)':

...
//-------------------------------------------------------------------------
/*!
\if english
Inserts a persistent object into the set behind the current position. If
the set objects are locked by the set, the object to be inserted is locked
with the lock mode of the set. If the set objects are observed by the set,
the object to be inserted is observed with the observation mode of the set.
\param[in] spNewObj The persistent object to be inserted in a GloSharedPtr.
\return A return value < 0 indicates an error.
\endif
\if german
Fügt ein persistentes Objekt in die Set hinter der aktuellen Position ein.
Wenn die Setobjekte durch die Set gesperrt sind, wird das einzufügende
Objekt mit den Sperrmodus des Sets gesperrt. Wenn die Setobjekte durch
die Set beobachtet werden, wird das einzufügende Objekt mit den
Beobachtungsmodus des Sets beobachtet.
\param[in] spNewObj Das einzufügende persistente Objekt in einem GloSharedPtr.
\return Ein Rückgabewert < 0 zeigt einen Fehler an.
\endif
*/
virtual int insert( GloSharedPtr<T> spNewObj );
//-------------------------------------------------------------------------
...