Design

Fragen

Typisierung
Stark statt schwach
Schnitstelle
Referenzen statt Zeiger
Ein-/Ausgabe
IOStreams statt Standard IO
Aufrufkonvention
C++ nach C statt C nach C++
Vererbung
Statisch (template) statt dynamisch (virtual)
Schnittstelle
Intuitive Operationen statt get- und set-Methoden
Richtung
Outside-in statt inside-out
Fehlerbehandlung
Ausnahmen oder Rückgabewert
Variablennamen
stl_style statt javaStyle.
Teststrategie
Unit-Test vor Code schreiben

Entwurfsmuster

RAII

Ressource Acquisition Is Initialisation: Betriebsmittel (Speicher, Dateien, Mutexe, Handles) werden ausschließlich im Konstruktur angefordert und im zugehörigen Destruktur freigegeben. Dies entbindet den Anwender von der fehlerträchtigen manuellen Freigabe. Der Code wird Ausnahme-sicher (exception safe). Zum Beispiel:

{
	std::ifstream is ("filename.txt");
	is.read (...);
} // Eingabestrom wird automatisch geschlossen.

statt (in Java):

{
	FileInputStream is = null;
	try {
		is.open ("filename.txt");
		is.read (...);
	} finally {
		// Eingabestrom muss explizit geschlossen werden.
		if (is != null) is.close ();
	}
}

PIMPL

Pointer to Implementation: Die Deklaration eines Klasse enthält nur einen Zeiger auf eine Struktur mit den Attributen. Auf diese Weise kann man die interne Repräsentation eines Objekts anpassen, ohne die Schnittstelle zu ändern.

foo.h

class Foo {
	struct pimpl;
	struct pimpl * p;
public:
	virtual ~Foo ();
	Foo ();
	Foo (const Foo & f);
	Foo & operator= (const Foo & f);
};

foo.cc

struct Foo::pimpl { // anything... };

Foo::~Foo ()
{
	delete p;
}

Foo::Foo () : p (new pimpl())
{
}

Foo::Foo (const Foo & f) : p (new pimpl (*(f.p)))
{
}

Foo &Foo::operator= (Foo f)
{
	std::swap (p, f.p);
	return *this;
}

NRVO

Named Return Value Optimization: Der Compiler erzeugt bei der Rückgabe von komplexen Objekten keine unnötigen Kopien, der Code wird lesbarer.

CRTP

Curiously Reoccuring Template Pattern: FIXME Template Meta-Programmierung

Todsünden

Zeiger oder Referenzen auf lokale Variablen zurückliefern.
Lokale Variablen liegen auf dem Stack und werden mit grosser Wahrscheinlichkeit bald wieder überschrieben. Verlasse Dich auf NRVO und liefere ein neues Objekt!
Zeiger oder Referenzen auf Klassenvariablen zurückliefern.
Dies durchbricht die Kapselung und die dadurch gewonnene Abstraktion. Wenn es gar nicht anders geht, liefere const-Referenzen!
Komplexe Objekte wie Container by value übergeben.
Dies erzeugt bei jedem Aufruf eine Kopie aller enthaltenen Elemente auf dem Stack. Objekte immer by reference übergeben!
Ressourcen außerhalb eines Konstruktors anfordern.
Führt zu unnötig komplexer Ausnahme-Behandlung oder verursacht Speicherlöcher und andere Ressourcen-Lecks. Verwende das RAII-Muster!