Pre-Inkrement ++

Der Pre-Inkrement-Operator erhöht den angegebenen Operanden um eine Einheit und speichert den Wert zurück in den Operanden. Für arithmetische Typen entspricht dies der Addition mit 1. Im Gegensatz zum Post-Increment-Operator steht der Operator ++ VOR dem Operanden und wird ausgeführt, BEVOR der Operand zurückgegeben wird.





5

6
#include <stdio.h>

int main(){
  int a = 5;
  printf("%d\n",  a);
  ++a;
  printf("%d\n",  a);
  return 0;
}

Siehe auch Post-Increment-Operator ++, Pre-Decrement-Operator --, Post-Decrement-Operator --

Details

Der Pre-Inkrement-Operator erwartet einen Operanden als lvalue und wird von rechts nach links abgearbeitet. Der Rückgabewert ist in C ein rvalue: Der Wert des (mittlerweile veränderten) Operanden, der angegeben wurde. In C++ ist der Rückgabewert ein lvalue: Der (mittlerweile veränderte) Operand selbst.

Zwar ist der Pre-Inkrement-Operator für sämtliche arithmetische Typen zulässig, jedoch trifft man ihn hauptsächlich bei Integer-Typen und bei Pointern an. Wenn der Pre-Inkrement-Operator auf einen Pointer angewendet wird, so wird der Pointer um eine Typ-Grösse erhöht.




1

2
int main(){
  int a[5] = {1, 2, 3, 4, 5};
  int* b = a;
  printf("%d\n",  *b);
  ++b;
  printf("%d\n",  *b);
  return 0;
}

Wenn der Operand als konstant deklariert ist, so gibt der Compiler einen Fehler wie etwa increment of read-only variable, aus. Anmerkung: Ein (nicht als konstant deklarierter) Pointer, der auf einen konstanten Wert zeigt, kann selbstverständlich inkrementiert werden.

Durch die Addition einer Einheit kann es bei arithmetischen Typen vorkommen, dass ein Overflow passiert, was bei Integer-Typen zu einem Wrap-Around führt


0
unsigned char a = 255;
printf("%d\n",  ++a);

Der Pre-Increment-Operator ist ein Operator mit Nebeneffekt, was bedeutet, dass der angegebene Operand sowohl gelesen, als auch geschrieben wird. Der Unterschied des Pre-Inkrement-Operators zum Post-Increment-Operator ist, dass der inkrementierte Wert in den Operanden zurückgeschrieben wird, BEVOR der Operand als Rückgabewert verwendet wird, wohingegen der Post-Inkrement-Operator den Operanden zuerst als Rückgabewert auffasst und ihn danach erhöht. Folgendes Beispiel verdeutlicht diesen Unterschied:


11
11
12
int a = 10;
printf("%d\n",  ++a);
printf("%d\n",  a++);
printf("%d\n",  a);

Überladen des Operators

Der Pre-Increment-Operator hat grundsätzlich die semantische Bedeutung einer Addition einer Einheit im mathematischem Sinne, jedoch sind auch andere, ähnliche semantische Bedeutungen möglich. Es hat sich zudem eingebürgert, den Increment-Operator als Navigations-Operator zu benutzen, wie er bei Iteratoren benötigt wird. Grundsätzlich ist der Pre-Increment-Operator zu verstehen als ein Operator, der den Operanden selbst verändert, allerdings erlaubt die Operatoren-Überladung auch jegliche andere Implementation.

Um bei den Inkrement-Operatoren zwischen der Pre- und der Post-Variante zu unterscheiden, wird bei der Post-Variante ein zusätzlicher int-Parameter deklariert. Das Ausprogrammieren der Post-Variante erweist sich zudem normalerweise als schwieriger als die Pre-Variante, da ein Objekt mit dem Inhalt VOR Anwendung des Operators zurückgegeben werden soll. Dies ist nebenbei bemerkt der Grund, wieso der Autor anstelle von ManderC++ den Titel Mander++C gewählt hat. Genauere Details über das Überladen der Post-Variante ist beim Post-Increment-Operator nachzulesen.

Die Prototypen für das Überladen des Pre-Increment-Operators sind die folgenden (Einschränkungen und Erläuterungen siehe Überladen von Operatoren):

inside class


outside class
Type operator ++();
Type operator ++() const;

Type operator ++(Type);

Da der Pre-Increment-Operator in C++ normalerweise einen lvalue zurückgibt, ist der Rückgabetyp der Überladung üblicherweise ein Referenz-Typ (&) der eigenen Klasse, wobei der Rückgabewert normalerweise mit return *this angegeben wird. Man beachte hierfür auch den Unterschied zum Post-Increment-Operator.

Der const-Prototyp macht auf den ersten Moment keinen Sinn, da bei einem Pre-Increment-Operator im herkömmlichen Sinne das betroffene Objekt immer verändert wird. Man beachte jedoch, dass diese semantische Bedeutung nicht zwingend eingehalten werden muss und ausserdem Felder von Klassen mittels der mutable-Speicherklasse deklariert werden können. Bei Auftreten beider Prototyp-Varianten in einer Klasse wird jedoch grundsätzlich (ohne die Notwendigkeit eines const-Aufrufes) die nicht-const-Überladung aufgerufen.

Im folgenden Beispiel wird ein Iterator für eine einfache Liste von Elementen präsentiert. Der überladene Pre-Inkrement-Operator lässt den Iteratoren zum nächsten Element der Liste wandern.




























100
200
300
#include <cstdio>

class Element{
public:
  int key;
  Element* next;
  Element* prev;
  Element(int newkey){key = newkey; next = NULL; prev = NULL;}
  void attach(Element& nextelem){
    nextelem.prev = this; next = &nextelem;
  }
  int getKey(){return key;}
};

class Iterator{
public:
  Element* cur;
  Iterator(Element& e){cur = &e;}
  Iterator& operator ++(){cur = cur->next; return *this;}
};

int main(){
  Element e1(100);
  Element e2(200); e1.attach(e2);
  Element e3(300); e2.attach(e3);
  Iterator e(e1);
  while(e.cur){
    printf("%d\n", e.cur->getKey());
    ++e;
  }
  return 0;
}