Klassen

Die Übersichtlichkeit der Seite wird durch Javascript erhöht. Ist dies aktiviert, werden die Texte unter den Überschriften durch Anklicken der Überschriften ein- und ausgeblendet.

Allgemein

Klassen sind beschreibungen von Objekten, die Eigenschaften und Funktionen enthalten. Alle Bestandteile einer Klasse sind vom Standard her privat, das bedeutet, sie können nur innerhalb der Klasse angesprochen werden. Um die Klasse nutzen zu können benörigt man auch immer einen öffentlich ansprechbaren Bereich. Dieser wird mit dem Schlüsselwort public definiert, so dass alles, was folgt öffentlich nutzbar ist. Möchte man in der Folge wieder Private Bestandteile definieren nutzt man das Schlüsselwort private.


class Klassenname{
  public:
    Typ elementfunktion1();
    Typ elementfunktion2();
  private:
    Typ attribut1;
    Typ attribut2;
    Typ interneFunktion();
};

nach oben

Klassendefinition

class Klassenname{ ... };

nach oben

Konstruktor

Ein Konstruktor ist eine besondere Klassenfunktion, die Speicherplatz für ein erzeugtes Objekt bereitstellt. Dabei wird der Kondstruktor automatisch vom System bereitgestellt. Sollen allerdings definierte Zustände übergeben werden, so ist dieser Konstruktor zu überschreiben:

Standardkonstruktor

class Klassenname{
public:
  Klassenname(){
    attribut1=0;
    attribut2=1;
  }
private:
  Typ attribut1;
  Typ attribut2;
};

Wird dann ein Objekt der Klasse deffiniert, werden die Atribute der Klassen wie definiert belegt:

Klassenname Objekt1;

Direkte Ininitialisierung

Die Attribute können auch ohne einen selbst geschriebenen Standard-Konstruktor mit Standardwerten versehen werden, indem die Werte direkt bei der Deklaration übergeben werden:

class Klassenname{
 public:
  ...
 private:
  attribut1 = 0;
  attribut2 {0};
};

nach oben

Allgemeine Konstruktoren

Allgemeine Konstruktoren ermöglichen es im Gegensatz zu Standardkonstruktoren Argumente entgegenzunehmen und können wie Funktionen auch überladen werden. Auch ein Allgemeiner Konstruktor verhindert die Erzeugung eines Standardkonstrukters durch das System.

class Klassenname{
public:
  Klassenname(Typ Argument1, Typ Argument2){
    attribut1 = Argument1;
    attribut2 = Argument2;
  }
private:
  Typ attribut1;
  Typ attribut2;
};

Objekte können dann wie folgt deffiniert werden:

Klassenname objekt1(70,90);
Klassenname objekt2 = {50,51};
Klassenname objekt3 {25,50};

Wenn es mehrere Allgemeine Konstruktoren gibt wird der richtige anhand der Anzahl und Datentypen aufgerufen.

Vorgegebene Parameterwerte

class Klassenname{
public:
  Klassenname( Typ argument1, Typ argument2 = 100){
    attribut1 = argument1;
    attribut2 = argument2;
}
private:
  Typ attribut1;
  Typ attribut2;
};

nach oben

Konstruktor Initialisierungsliste

Dies bringt Laufzeitvorteile:

class Klassenname{
public:
  Klassenname(Typ Parameter1, Typ Parameter2)
  : attribut1 {Parameter1}, attribut2 {Parameter2} {
   // ggf Anweisungen oder leerer Block
  }
private:
 Typ attribut1;
 Typ attribut2;
};

nach oben

Sequenzkonstruktor

Mit Hilfe von initializer_list ist es möglich eine Liste mit beliebig vielen Werten entgegenzunehmen. Beispiel:

#include<initializer_list>
#include<vector>

class Zahlenfolge{
public:
  Zahlenfolge(std::initializer_list<int> liste){
    folge.assign(liste);
  }
private:
  std::vector<int> folge;
};

Die Zuweisung einer Zahlenfolge erfolgt dann immer in geschweiften Klammern:

Zahlenfolge z1{1,2,3,4,5,6,7,8,9};

Hat man einen weitern Konstruktor, der ein oder zwei Parameter entgegen nimmt, so wird dieser in dem Fall nur aufgerufen, wenn die Parameter in runden Klammern übergeben werden.

nach oben

Kopierkonstruktor

Der Kopierkonstruktor dient dazu, ein Objekt mit einem anderen zu initialisieren. Er entspricht einem Algemeinen Konstruktor, dem eine Referenz auf ein Objekt der selben Klasse übergeben wird.

class Klassenname{
public:
  Klassenname(const Klassenname& Objekt)
  : attribut1{Objekt.attribut1}, attribut2{Objekt.attribut2} {
  }
private;
  Typ attribut1;
  Typ attriput2;

};

Der hier gezeigte Kopierkonstruktor entspricht dem vom System automatisch erzeugten. Mit dem Kopierkunstruktor kann dann ein Objekt wie folgt erzeugt werden:

Klassenname Objekt1(19,39);
Klassenname ObjektKopie1 = Objekt1
Klassenname ObjektKopie2(Objekt1); 

nach oben

Typumwandlungskonstruktor

Der Typumwandlungskonstruktor dient zum Umwandeln anderer Datentypen in die gewünschte Klasse. Dabei wird als Argument ein Objekt einer anderen Klasse üergeben.

class Klassenname{
public:
  [explicit] Klassenname(const Typ& Objekt) {
    // Prozedur, die die Attribute aus dem 
    // übergebenen Objekt ermittelt und
    // entsprechend setzt
  }
private:
  Typ attribut1;
  Typ attribut2;
};

explicit

Wird das Schlüsselwort explicit vorangestellt, wird eine automatische Typumwandlung des Compilers verhindert. Für diesen Fall müsste der Aufruf der Typumwandlung expliziet angeforedert werden:

string wo("20,400");
Ort dort = Ort(wo);

Lässt mann dies weg, so ist die Typprüfung eingeschränkt, folgende Zuweisung ist dann möglich und führt in diesem Fall zu einem korrekten Ergebnis:

string wo("20,400");
Ort dort = wo;

nach oben

Konstruktorsteuerung / default, delete

default

Mit default kann die Nutzung des Compiler-generierten Konstruktors ermöglicht werden, auch wenn es schon einen allgemeinen Konstruktor gibt.

class Klassenname {
public:
  Klassenname() = default;
  Klassenname(int i=0)
  : attribut1{i} {}

private:
  int attribut1;
};

nach oben

delete

Mit delete ist es möglich die automatische Erzeugung eines Konstruktors durch den Compiler zu verbieten.

class Klassenname {
public:
  Klassenname(const Klassenname&) = delete; //Kopieren verbieten
private:
  Typ Attribut1;
};

nach oben

Delegierter Konstruktor

Der Sinn besteht darin, die Initialisierung von Attributen ohne Code-Duplikation zu erreichen.

class Klassenname{
public:
  Klassename(Typ parameter1, Typ parameter2)
  : Attribut1{parameter1}, Attribut2{Parameter2} {} // Konstruktor1

  Klassenname()
  : Klassenname(1,42){} // Delegation an Konstruktor 1
private:
  Typ Attribut1;
  Typ Attribut2;
};

nach oben

constexpr-Konstruktor und Methoden

Mit constexpr wird die Berechnung sofern möglich zu Compilationszeit bereits angestoßen. Dies schafft Laufzeitvorteile. Ein constexpr-Objekt ist immer auch const. Seine Erzeugung setzt voraus:

  • einen constexpr-Konstruktor,
  • literale Argumente und
  • Code, der keine Ausführung zur Laufzeit voraussetzt

Am Beispiel eines Kreises:

#include <iostream>
#include <pi.h>

class Kreis{
public:
  constexpr Kreis(double r)
  : radius{r}{
    if (radius<0){
      std::cerr << "Fehler: negativer Radius" << std::endl;
      exit(1);
    }
  }

  constexpr double getRadius() const {
    return radius
  }

  constexpr double getFlaeche() const {
    return radius * radius * pi<double>;
  }

  constexpr void setRadius(double r){
    radius=r;
  }
private:
  double radius;
};

template<typename T> constexpr T pi = 3.14159265358979323846264338328L;

Die Klasse kann dann wie folgt verwendet werden:

constexpr Kreis ck(100.0);
constexpr double cr = ck.getRadius();
constexpr double cf = ck.getFlaeche();
  

nach oben

Destruktor

Destruktoren werden bei der Löschung eines Objektes aufgerufen. Sie werden automatisch durch den Compiler erzeugt, können aber überschrieben werden. Durch Destruktoren sollen die Ressourcen für ein Objekt wieder freigegeben werden. Die Reihenfolge des Aufrufes der Destruktoren ist umgekehrt wie die der Konstruktoren. (Last in First out) Destruktoren haben keine Argumente und Rückgabetypen

class Klassenname{
public:
  ~Klassenname(){
    // Code der bei der Zerstörung des Objektes ausgeführt werden soll
  }
};

nach oben