Warum es Funktionen gibt
Eine Funktion ist ein benannter Codeblock, den du bei Bedarf ausführen kannst, indem du ihn aufrufst. Anstatt dieselbe Logik an mehreren Stellen zu wiederholen, schreibst du sie einmal, gibst ihr einen Namen und rufst diesen Namen überall dort auf, wo du sie brauchst. Das hält Programme kürzer, leichter lesbar und leichter korrigierbar – ändere die Logik an einer Stelle, und jeder Aufrufer bekommt die Aktualisierung.
Du rufst die ganze Zeit bereits eine Funktion auf: main. Sie ist der Einstiegspunkt, von dem aus jedes C++-Programm startet. Jetzt schreibst du deine eigenen. Die Schleifen, die du zuvor gesehen hast, etwa die bereichsbasierte for-Schleife, leben oft innerhalb von Funktionen, sodass du ein ganzes Stück Logik über seinen Namen wiederverwenden kannst.
Anatomie einer Funktion
Jede Funktion hat vier Bestandteile: einen Rückgabetyp, einen Namen, eine Parameterliste in Klammern und einen Rumpf in geschweiften Klammern.
int add(int a, int b) { // Rückgabetyp | Name | Parameter
return a + b; // Rumpf
}
intist der Rückgabetyp – die Art von Wert, die die Funktion zurückgibt.addist der Name, mit dem du sie aufrufst.(int a, int b)sind die Parameter – die Eingaben, die der Aufrufer liefert.- Die geschweiften Klammern enthalten den Rumpf, den Code, der beim Aufruf ausgeführt wird.
Hier in einem vollständigen Programm. Die Funktion oberhalb von main zu definieren bedeutet, dass main sie sieht, wenn sie sie aufruft.
Der Aufruf add(2, 3) führt die Funktion mit a = 2 und b = 3 aus, und der gesamte Ausdruck wird zum zurückgegebenen Wert. Du kannst ihn in einer Variablen speichern oder direkt innerhalb eines anderen Ausdrucks verwenden, wie es die zweite cout-Zeile tut.
Einen Wert zurückgeben
Die return-Anweisung tut zweierlei: Sie gibt einen Wert an den Aufrufer zurück und beendet die Funktion sofort. Code nach einem return wird nicht ausgeführt – die Steuerung springt direkt dorthin zurück, wo die Funktion aufgerufen wurde.
Der Typ des zurückgegebenen Werts muss zum deklarierten Rückgabetyp passen (oder sich in ihn umwandeln lassen). Eine als int deklarierte Funktion sollte einen int zurückgeben; nichts zurückzugeben oder ohne return über das Ende hinauszulaufen, ist bei jeder Nicht-void-Funktion ein Fehler.
void-Funktionen
Nicht jede Funktion erzeugt einen Wert. Wenn eine Funktion nur etwas tut – eine Ausgabe ausgibt, einen Zustand aktualisiert –, ist ihr Rückgabetyp void. Eine void-Funktion kann ein bloßes return; verwenden, um vorzeitig auszusteigen, oder einfach bis zur schließenden Klammer durchlaufen.
Den Rückgabewert einer void-Funktion verwenden zu wollen (int x = greet("Ada");) ist ein Kompilierfehler, weil es keinen Wert zum Zuweisen gibt. Ein häufiger Fehler ist, return someValue; in einer void-Funktion zu schreiben; auch das lehnt der Compiler ab.
Deklarationen vs. Definitionen
C++ liest eine Datei von oben nach unten, daher muss eine Funktion standardmäßig vor dem Code erscheinen, der sie aufruft. Wenn diese Reihenfolge unpraktisch ist, teilst du die Funktion in eine Deklaration (auch Prototyp genannt) und eine Definition auf.
Eine Deklaration nennt die Signatur der Funktion und endet mit einem Semikolon – ohne Rumpf. Sie verspricht dem Compiler: „Diese Funktion existiert; so rufst du sie auf.“ Die vollständige Definition kann dann später kommen, sogar nach main.
Ohne den Prototyp in Zeile 4 würde der Compiler square(5) innerhalb von main erreichen, bevor er square jemals gesehen hat, und der Build würde fehlschlagen. Prototypen sind auch die Art und Weise, wie Header-Dateien es vielen Quelldateien ermöglichen, dieselben Funktionen gemeinsam zu nutzen. Beachte, dass die Namen der Parameter in einer Deklaration optional sind: int square(int); funktioniert genauso gut; für den Compiler zählen nur die Typen.
Häufige Fehler
Ein paar Fallen erwischen Anfänger immer wieder:
- Aufrufen vor dem Deklarieren. Wenn du den Fehler „
addwas not declared in this scope“ bekommst, ist die Funktion unterhalb ihres ersten Aufrufs definiert und hat keinen Prototyp. Verschiebe die Definition nach oben oder füge einen Prototyp hinzu. - Das return vergessen. Das Ende einer Nicht-
void-Funktion ohnereturnzu erreichen, ist undefiniertes Verhalten – der Aufrufer erhält Müll. Kompiliere mit aktivierten Warnungen (-Wall), dann weist der Compiler darauf hin. - Definieren vs. Aufrufen. Eine Definition hat einen Rumpf in geschweiften Klammern und kein abschließendes Semikolon. Eine Deklaration hat ein Semikolon und keinen Rumpf. Sie zu verwechseln – etwa ein Semikolon direkt hinter die Parameterliste einer Funktion zu setzen, die du definieren wolltest – erzeugt verwirrende Fehler.
- Den Rückgabewert ignorieren.
add(2, 3);allein in einer Zeile kompiliert, aber die berechnete Summe wird stillschweigend weggeworfen. Stelle sicher, dass du tatsächlich verwendest, was eine Funktion zurückgibt.
// Sieht aus wie eine Definition, aber das verirrte ; macht daraus eine
// Deklaration gefolgt von einem übrig gebliebenen Block – ein häufiger Tippfehler:
int triple(int n); // <- dieses ; beendet die Anweisung
{
return n * 3; // n ist hier nicht definiert; dieser Block ist nun verwaist
}
Als Nächstes: Funktionsparameter
Du hast gesehen, wie Funktionen Eingaben über ihre Parameterliste entgegennehmen, aber da steckt noch viel mehr dahinter. Die nächste Seite geht tiefer auf Funktionsparameter ein: Übergabe als Wert gegenüber Übergabe per Referenz, Standardargumente, const-Parameter und wie diese Wahl beeinflusst, ob deine Funktion die Daten des Aufrufers ändern kann.
Häufig gestellte Fragen
Wie schreibt man eine Funktion in C++?
Gib ihr einen Rückgabetyp, einen Namen, Klammern für die Parameter und einen Rumpf in geschweiften Klammern: int add(int a, int b) { return a + b; }. Rufe sie über ihren Namen mit Argumenten auf, etwa add(2, 3). Wenn die Funktion nichts zurückgibt, verwende void als Rückgabetyp.
Was ist der Unterschied zwischen einer Funktionsdeklaration und einer Definition in C++?
Eine Deklaration (oder ein Prototyp) teilt dem Compiler Name, Rückgabetyp und Parameter einer Funktion mit und endet mit einem Semikolon: int add(int a, int b);. Eine Definition liefert zusätzlich den Rumpf in geschweiften Klammern. Du kannst eine Funktion vor main deklarieren und sie später definieren – die Deklaration erlaubt es, sie aufzurufen, bevor die Definition erscheint.
Was passiert, wenn eine C++-Funktion keinen Wert zurückgibt?
Bei einer void-Funktion nichts – sie endet einfach. Bei einer Nicht-void-Funktion ist es jedoch undefiniertes Verhalten, das Ende ohne return zu erreichen: Der Aufrufer erhält einen Müllwert und das Programm kann sich fehlerhaft verhalten. Die meisten Compiler warnen davor; gib bei einer Nicht-void-Funktion auf jedem Pfad einen Wert zurück.