Default-Parameter
Die nachfolgenden Ausführungen beziehen sich sowohl auf Methoden wie auch auf Funktionen. Wenn im Folgenden von Funktionen gesprochen wird, sind damit stets auch Methoden gemeint.
Definition des Default-Parameters
Werden für Parameter einer Funktion häufig die gleichen Werte übergeben, können für diese Parameter Defaultwerte vorgegeben werden. Argumente, für die ein Default-Parameter definiert ist, können beim Aufruf der Funktion entfallen. In diesem Fall enthält der Parameter den Defaultwert.
Um einen Parameter mit einem Defaultwert zu versehen, wird nach dem Parameternamen der Zuweisungsoperator angegeben, gefolgt vom Defaultwert. Im Beispiel wird dem letzte Parameter symbol das Zeichen '#' als Defaultwert zugewiesen.
void DrawRect(short xPos, short yPos,
short width, short height,
char symbol = '#')
{...}
Besitzt ein Parameter einen Defaultwert, müssen alle danach folgenden Parameter ebenfalls einen Defaultwert besitzen. Dies ist bei der Spezifikation der Funktion zu beachten.
Als Defaultwerte sind nur Literale oder Konstanten zugelassen und der Datentyp des Defaultwertes muss mit dem Datentyp des Parameters übereinstimmen oder sich in diesen konvertieren lassen.
Die erste Funktionsdefinition im nachfolgenden Beispiel ist syntaktisch in Ordnung, da die beiden Parameter height und symbol jeweils einen Defaultwert erhalten. Die zweite Funktionsdefinition hingegen ist fehlerhaft. Der Parameter height erhält hier zwar einen Defaultwert, der nachfolgende Parameter symbol dagegen nicht.
// Das ist in Ordnung
void DrawRect1(short xPos, short yPos, short width,
short height = 1, char symbol = '#')
{...}
// Aber dies erzeugt einen Fehler
void DrawRect2(short xPos, short yPos, short width,
short height = 1, char symbol)
{...}
Funktionsdeklaration/-definition
Die Definition von Default-Parametern kann auf zweierlei Arten erfolgen:
- Bei der Deklaration der Funktion oder
- bei der Definition der Funktion
Jedoch dürfen die Defaultwerte nur an einer Stelle angegeben werden, entweder bei der Deklaration oder bei der Definition.
// Default-Parameter bei der Deklaration
// Deklaration
void DrawRect1(short xPos, short yPos, short width,
short height = 1, char symbol = '#');
// Definition der Funktion
void DrawRect1(short xPos, short yPos, short width,
short height, char symbol)
{...}
// Default-Parameter bei der Definition
// Deklaration
void DrawRect2(short xPos, short yPos, short width,
short weight, char symbol);
// Definitionen der Funktion
void DrawRect2(short xPos, short yPos, short width,
short height = 1, char symbol = '#')
{...}
Erfolgt die Definition der Funktion in einem Modul, spielt es keine Rolle, ob die Default-Parameter bei der Deklaration oder Definition der Funktion angegeben werden.
Ist die Funktion nicht in einem Modul definiert, sollten die Default-Parameter nach Möglichkeit bei der Deklaration angegeben werden. In der Regel werden Funktionsdeklarationen bei größeren Projekten in einer Header-Datei zusammengefasst, die von den Quellcode-Dateien eingebunden werden, welche die Funktion aufrufen. Und nur wenn die Default-Parameter in dieser Header-Datei angegeben sind, sind sie in den Quellcode-Dateien sichtbar.
Funktionsaufruf
Beim Aufruf einer Funktion mit Default-Parametern ist beachten, wenn für einen der Default-Parameter ein Argument übergeben wird, sind für alle davor stehenden Parameter ebenfalls Argumente zu übergeben.
Sehen wir uns einige Aufrufe einer Funktion mit fünf Parametern an, deren letzte zwei Parameter Defaultwerte besitzen.
// Funktionsdefinition
void DrawRect(short xPos, short yPos, short width,
short height = 1, char symbol = '#')
{...}
// Erlaubte Aufrufe
// entspricht dem Aufruf DrawRect(10,10,100,1,'#')
DrawRect(10,10,100);
// entspricht dem Aufruf: DrawRect(10,10,100,100,'#')
DrawRect(10,10,100,100);
// Aber dies ist nicht erlaubt!
DrawRect(10,10,100, ,'*');
Der erste Aufruf übergibt an die Funktion 3 Argumente. Die beiden beim Aufruf fehlenden Argumente für height und symbol werden dann mit den Defaultwerten belegt. Der zweite Aufruf übergibt zusätzlich height, was dazu führt, dass nur der Parameter symbol mit seinem Defaultwert belegt wird. Der letzte Aufruf im Beispiel oben ist fehlerhaft, da für den letzten Parameter ein Argument übergeben wird und damit sind für alle links davor stehenden Parameter ebenfalls Argumente zu übergeben.
Funktionserweiterung durch Default-Parameter
Default-Parameter eignen sich gut dazu, die Funktionalität einer bestehenden Funktion zu erweitern, ohne dass existierende Funktionsaufrufe angepasst werden müssen. Das nachfolgende Beispiel enthält eine Funktion SortIt(), die ein unsigned char-Feld in aufsteigender Reihenfolge sortieren soll.
#include <print>
// Funktion zum Sortieren von char-Daten
void SortIt(unsigned char* array, size_t noOfElements)
{
// Datenfeld aufsteigend sortieren
std::println("Sortierung A...Z");
}
int main()
{
const unsigned int NOELEMENTS = 10;
unsigned char data[NOELEMENTS];
// ... Datenfeld bearbeiten
// Feld sortieren
SortIt(data, sizeof data);
}
Sortierung A...Z
Im weiteren Verlaufe der Entwicklung ergibt sich die nun Anforderung, das unsigned char-Feld ebenfalls in fallender Reihenfolge zu sortieren. Hierzu wird die Funktion um einen zusätzlichen Parameter erweitert, der die Sortierrichtung festlegt.
Normalerweise wären nun alle bisherigen Funktionsaufrufe anzupassen. Mithilfe eines Default-Parameters es jedoch möglich, lediglich die Funktion an die neue Anforderung anzupassen und bestehende Funktionsaufrufe unverändert zu lassen. Dazu wird der für die Sortierrichtung zusätzliche Parameter mit einem Defaultwert versehen, der die bisherige aufsteigende Sortierrichtung festlegt. Wie bekannt, können beim Funktionsaufruf Argumente für Parameter mit einem Defaultwert weggelassen werden. D.h., wird die Funktion wie bisher mit nur einem Argument aufgerufen, wird das unsigned char-Feld aufsteigend sortiert. Soll das Feld dagegen fallend sortiert werden, ist beim Aufruf der Funktion ein vom Defaultwert abweichender Wert anzugeben.
#include <print>
// Funktion zum Sortieren von char-Daten
void SortIt(unsigned char* array, size_t noOfElements, bool dir=true)
{
if (dir)
{
// Datenfeld aufsteigend sortieren
std::println("Sortierung A...Z");
}
else
{
// Datenfeld absteigend sortieren
std::println("Sortierung Z...A");
}
}
int main()
{
const unsigned int NOELEMENTS = 10;
unsigned char data[NOELEMENTS];
// ... Datenfeld bearbeiten
// Feld sortieren (default=aufsteigend)
SortIt(data, sizeof data);
// Feld sortieren abfallend
SortIt(data, sizeof data, false);
}
Sortierung A...Z
Sortierung Z...A
Übungen
defpar_01:
Es ist eine Funktion für die Ausgabe einer Linie oder Rechtecks zu erstellen. An die Funktion sind die Breite und Höhe sowie das zum 'Zeichnen' zu verwendende Zeichen zu übergeben.
Standardmäßig soll eine Line mit dem Zeichen '#' gezeichnet werden.
Geben Sie eine Line mit der Länge 10 und ein 5x5 Recheck mit dem Standardzeichen aus. Zum Schluss ist noch eine Line mit der Länge 9 und dem Zeichen '-' auszugeben.
##########
#####
#####
#####
#####
#####
---------
defpar_02:
Erstellen Sie eine Klasse zur Darstellung eines Rechtecks. Das Rechteck soll die Eigenschaften Größe, Position und Farbe besitzen, wobei sich die Farbinformation aus einen Rot-, Grün- und Blauanteil zusammensetzt. Die Farbeigenschaften sind als unsigned char-Daten abzulegen und alle anderen Eigenschaften als short-Daten.
Das Rechteck soll verschoben und in seiner Größe verändert werden können. Zusätzlich soll die Farbe des Rechtecks einstellbar sein.
Des Weiteren ist eine Methode zu schreiben, um die Eigenschaften des Rechtecks (wie unten dargestellt) auszugeben.
Für die Initialisierung der Eigenschaften des Rechtecks ist eine entsprechende Methode zu verwenden. Hierbei soll es möglich sein, ein Rechteck ohne Angabe einer Farbinformation anzulegen. In diesem Fall ist die Farbinformation mit dem Defaultwert 0x10 zu belegen.
Legen Sie zwei Rechtecke an, ein globales und ein lokales innerhalb der main() Funktion. Das globale Rechteck soll die Standardfarbe erhalten und das lokale eine beliebige andere Farbe.
Geben Sie beide Rechtecke aus. Anschließend ist das erste Rechteck zu verschieben und das zweite in seiner Größe und Farbe zu verändern. Geben Sie zur Kontrolle die veränderten Rechtecke erneut aus.
1. Rechteck:
Position: 10,10
Groesse : 640,480
RGB-Wert: 0x10,0x10,0x10
2. Rechteck:
Position: 100,50
Groesse : 800,600
RGB-Wert: 0x80,0x80,0x80
1. Rechteck:
Position: 20,20
Groesse : 640,480
RGB-Wert: 0x10,0x10,0x10
2. Rechteck:
Position: 100,50
Groesse : 1024,786
RGB-Wert: 0xc0,0xc0,0xc0