Benutzerdefinierte Typen als Parametertypen (Benutzerdefinierte Typen als Parametertypen), Lektion, Seite 721062
https://www.purl.org/stefan_ram/pub/benutzerdefinierte_parameter_c++ (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C++-Kurs

Benutzerdefinierte Typen als Parametertypen

Wie schon im Grundkurs an Hand von »::std::string« gezeigt, kann der Typ eines Parameters auch ein benutzerdefinierter Typ sein.

Die Initialisierung von Parametern durch Argumentwerte gilt als Kopier-Initialisierung.

Der Parameter wird initialisiert wie bei einer Kopier-Initialisierung »::std::string const s = "alpha"«.

instance_parameter.cpp
#include <iostream> 
#include <string>
void print( ::std::string const s ){ ::std::cout << s << '\n'; }
int main(){ print( "alpha" ); }

::std::cout
alpha

Das folgende Programm zeigt, daß als Argument auch eine geschweifte-Klammer-Initialisierungsliste erlaubt ist. Der Parameter wird dann damit initialisiert wie bei einer Kopier-Initialisierung »::std::string const s = { "alpha" }«.

instance_parameter.cpp
#include <iostream> 
#include <string>
void print( ::std::string const s ){ ::std::cout << s << '\n'; }
int main(){ print( { "alpha" } ); }

::std::cout
alpha

Die Aufrufe mit Typwandlung wären also nicht gestattet, wenn diese explizit wäre.

instance_parameter.cpp
#include <iostream> 
#include <string>
void print( ::std::string const s ){ ::std::cout << s << '\n'; }
int main(){ print( { 65, 66 } ); }

::std::cout
AB

Dies verhält sich wie eine Kopierinitialisierung mit Initialisierungsliste »::std::string const s = { 65, 66 }«

Guidelines
GUIDELINE: non-fundamental types are passed by const reference (Hier kommt heute auch by value in Frage, wenn ohnehin eine Kopie benötigt wird)
GUIDELINE: types passed by value: iterators, function objects (including predicates), built-in types
GUIDELINE: where there are output parameters the parameters are passed by reference, not by pointer

Referenzparameter

Wie bisher beschrieben, kann eine Variable  durch eine Referenzdefinition  so initialisiert werden, daß sie ein schon vorhandenes Objekt verwendet. Auch ein Parameter  kann so initialisiert werden, wenn er als Referenzparameter  definiert wird.

referenzparameter.cpp
#include <iostream> 
#include <ostream> 
#include <initializer_list>
void ausgabe( int const & parameter ) 
{ std::cout <<  
&parameter << ':' <<  
parameter << '\n'; }
int main() 
{ int o = 7; std::cout << &o << '\n'; 
ausgabe( o ); }

std::cout
006BFDF4 
006BFDF4:7

Der Wert  eines Argumentes steht in der erzeugten Inkarnation der aufgerufenen Funktion als Wert des Parameters zur Verfügung. Daher wird der Wert "7" aus dem Objekt "o" nach dem Aufruf "ausgabe( o )" der Funktion "ausgabe" zugänglich sein.

Wenn ein Parameter einer Funktion als Referenzparameter deklariert wurde, dann wird für diesen Parameter bei Aufrufen der Funktion ein besonders Übergabeverfahren eingesetzt: Die Referenzübergabe.

Bei der Referenzübergabe wird Information über das Argumentobjekt  (und nicht nur sein Wert) an die Inkarnation der Funktion übergeben. Der Aufruf »ausgabe( o )« übergibt also Information über das ganze Objekt "o" an die Funktion »ausgabe«. Das sieht man auch daran, daß Adressen und  Wert des Objektes der Funktion im Programm »referenzparameter.cpp« bekannt sind.

referenzparameter1.cpp
#include <iostream> 
#include <ostream> 
#include <initializer_list>
void ausgabe( int const & parameter ) 
{ std::cout <<  
&parameter << ':' <<  
parameter << '\n'; }
int main() 
{ ausgabe( 7 ); }

std::cout
006BFDF4:7

Wenn die Referenz konstant  ist, kann auch ein Wert („Rechtswert“) als Argument angegeben werden, zu dem dann automatisch ein vorübergehendes Objekt erzeugt wird. Die Veränderung  eines vorübergehenden anonymen Objektes ergäbe keinen Sinn, weil auf solch ein Objekt nach der ersten Verwendung kein weiterer Zugriff mehr möglich ist. Wenn ein Parameter für eine konstante  Referenz steht, dann besagt dies, daß über diesen Parameter auch gar keine Veränderungen des Objektes erfolgen sollen. Daher ist es dann möglich, ein vorübergehendes Objekt für diesen Parameter zu verwenden.

Der Aufruf "ausgabe( 7 )" wäre bei einem Parameter vom Typ einer nicht-konstanten Referenz nicht möglich, da der Ausdruck "7" kein Objekt  notiert, sondern einen Wert (ein Wert kann nicht verändert werden). Ist der Referenzparameter jedoch konstant, so wird ein vorübergehendes Objekt  erzeugt, mit dem Wert "7" initialisiert und vorübergehend (während der Inkarnation der Funktion "ausgabe") für den Parameter verwendet. Das geschieht genau so, wie es auch bei einer durch eine konstante Referenz erzeugten Variablen geschehen würde, die beispielsweise mit "int const & v( 2 );" definiert wird.

Bei größeren Objekten würde es viel Zeit kosten, wenn deren Wert an eine Funktion übergeben werden würde, weil ein Wert eines größeren Objektes viel Speicher umfassen kann, der dabei kopiert  werden müßte. Daher ist es in C++  üblich, größere Objekte als Referenz zu übergeben. Damit dann aber auch weiterhin Rechtswerte als Argument angegeben werden können, wird dann oft eine konstante  Referenz als Parameter verwendet.

referenzparameter2.cpp
#include <iostream> 
#include <ostream> 
#include <initializer_list>
void ausgabe( int const & parameter ) 
{ std::cout <<  
&parameter << ':' <<  
parameter << '\n'; }
int main() 
{ int o = 7; std::cout << &o << '\n'; 
ausgabe( o );  
ausgabe( o + 1 ); }

std::cout
006BFDF4 
006BFDF4:7 
006BFDF0:8

Auch der Ausdruck "o + 1" im Programm »referenzparameter2.cpp« ist kein Objekt. Trotzdem kann auch er als Argument einer Funktion mit einem konstanten Referenzparameter verwendet werden, denn es wird wieder ein vorübergehendes Objekt erzeugt und mit dem Wert des Ausdrucks initialisiert.

Nichtkonstante Referenzparameter

Ein Referenzparameter kann auch nichtkonstant  sein. In diesem Fall gilt alles vorher Gesagte, nur daß dann als Argument nur Objekte  („Linkswerte“) in Frage kommen. Es werden dann keine vorübergehenden Objekte erzeugt.

referenzparameter3.cpp
#include <iostream> 
#include <ostream> 
#include <initializer_list>
void ausgabe( int & parameter ) 
{ std::cout <<  
&parameter << ':' <<  
parameter << '\n'; }
int main() 
{ int o{ 7 }; std::cout << &o << '\n'; 
ausgabe( o ); /* Übergabe des Objektes o */ 
/* ausgabe( 7 ); */ /* nicht erlaubt */ }

std::cout
006BFDF4 
006BFDF4:7

Bei einem nichtkonstanten Referenzparameter ist es aber auch möglich, daß eine Funktion den Wert in einem Argumentobjekt verändert. In solch einem Fall kann die Funktion aber nicht die Adresse oder den Datentyp des Objekts ändern, sondern nur den Wert (Inhalt) des Objekts. Da die Funktion dann aber keine Kopie des Wertes sondern eine Referenz auf das Argumentobjekt selber hat, kann sie dessen Wert auch dauerhaft veränderndie Veränderung bleibt nach dem Ende der Inkarnation der Funktion bestehen.

referenzparameter4.cpp
#include <iostream> 
#include <ostream>
void eight( int & parameter ){ parameter = 8; }
void show( int const & i ) 
{ std::cout << &i << ':' << i << '\n'; }
int main() 
{ int o{ 7 }; show( o ); eight( o ); show( o ); }

std::cout
006BFDF4:7 
006BFDF4:8

Ein Problem kann es werden, wenn der Benutzer einer Funktion sich nicht bewußt ist, daß eine Funktion den Wert eines bestimmten Argumentes verändern kann. Daß dies geschieht, ist nämlich eher selten. Manche sehen dies als ein Argument gegen Referenzparameter an. Andere weisen darauf hin, daß der Benutzer einer Funktion deren Spezifikation kennen sollte und dieser ja entnehmen kann, ob die Funktion ein bestimmtes Argumentobjekt verändern könnte.

Variablenparameter

Bei einem konstanten Referenzparameter  wird ein Objekt übergeben. Wird ein Rechtswert  als Argument angegeben, dann wird ein vorübergehendes Objekt  erzeugt.

Es ist auch möglich, immer  ein vorübergehendes Objekt für einen Parameter zu erzeugen. In diesem Fall wird der Parameter nicht wie eine Referenz, sondern wie eine Variable definiert. Genau wie bei einer Variablendefinition, wird dann immer ein neues Objekt  für den Parameter erzeugt und der Wert  des Argumentes wird in dieses neue Parameterobjekt kopiert. Da hierbei nur der Wert übergeben wird und nicht das gesamte Objekt wird diese Art der Parameterübergabe im Englischen auch als “by value ” (mit Wertübergabe) bezeichnet. Das Parameterobjekt kann dann in der Funktion verändert werden, aber dies hat keine Auswirkungen auf den Wert des Argumentobjekts.

parameter.cpp
#include <iostream> 
#include <ostream> 
#include <initializer_list>
void ausgabe( int parameter ) 
{ std::cout <<  
&parameter << ':' <<  
parameter << '\n'; 
parameter = 8;  
std::cout << parameter << '\n'; }
void show( int const & i ) 
{ std::cout << &i << ':' << i << '\n'; }
int main() 
{ int argument{ 7 }; show( argument ); 
ausgabe( argument ); show( argument ); }

std::cout
006BFDF4:7 
006BFDA4:7 

006BFDF4:7

Ein Referenzparameter  bezieht sich direkt auf das beim Aufruf angegebene Objekt.

Referenzparameter
.--------------------. 
| Argumentobjekt | Referenz auf Argumentobjekt 
| |<------------------------------. 
| | | 
'--------------------' | 
| | 
| | 
| | 
.--------------------. .--------------------. 
| Aufruf | | Referenzparameter | 
| | | | 
| | | | 
'--------------------' '--------------------'

Für einen Variablenparameter  wird bei der Inkarnation einer Funktion ein vorübergehendes Parameterobjekt erzeugt, der Wert des Argumentobjektes wird daraufhin in das Parameterobjekt kopiert. Am Ende der Inkarnation wird das vorübergehende Parameterobjekt wieder aufgelöst.

Variablenparameter
.--------------------.                    .--------------------. 
| Argumentobjekt | | Parameterobjekt | 
| |------------------->| - Erzeugung | 
| | Kopieren des | - Vernichtung | 
'--------------------' Wertes '--------------------' 
| ^ 
| | 
| | 
.--------------------. .--------------------. 
| Aufruf | | Variablenparameter | 
| | | | 
| | | | 
'--------------------' '--------------------'

Konstante Variablenparameter

Oft ist es sinnvoll, den Werte eines Variablenparameters nicht zu verändern, da dieser eine von außen in die Inkarnation der Funktion gegebene Information darstellt. Dann empfiehlt es sich diesen Parameter mit »const« zu kennzeichnen, wodurch dessen Wert nicht mehr verändert werden kann.

constparameter.cpp
#include <iostream> 
#include <ostream> 
#include <initializer_list>
void ausgabe( int const parameter ) 
{ ::std::cout <<  
&parameter << ':' <<  
parameter << '\n'; }
void show( int const & i ) 
{ std::cout << &i << ':' << i << '\n'; }
int main() 
{ int o{ 7 }; show( o ); 
ausgabe( o ); show( o ); }

std::cout
006BFDF4:7 
006BFDA4:7 
006BFDF4:7

Wahl der Parameter-Art

Fundamentale Zahlenobjekte und Zahlenwerte brauchen relativ wenig Speicherplatz, sind leicht zu erzeugen und aufzulösen. Die Verwaltung eines Referenzparameters erfolgt intern meistens durch eine Objektadresse, was aufwendiger  ist als eine direkte Kopie eines Zahlenwertes. Daher ist es für Zahlen  (Gleitkommazahlen und Ganzzahlen) effizienter, in konstanten Variablenparameter  gehalten zu werden.

Soll ein beim Aufruf angegebenes Objekt verändert  werden, dann muß  jedoch ein nichtkonstanter Referenzparameter  eingesetzt werden.

Die konstanten Referenzparameter  haben auch ein wichtiges Anwendungsgebiet, das aber erst später behandelt werden wird.

Seiteninformationen und Impressum   |   Mitteilungsformular  |   "ram@zedat.fu-berlin.de" (ohne die Anführungszeichen) ist die Netzpostadresse von Stefan Ram.   |   Eine Verbindung zur Stefan-Ram-Startseite befindet sich oben auf dieser Seite hinter dem Text "Stefan Ram".)  |   Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram. Schlüsselwörter zu dieser Seite/relevant keywords describing this page: Stefan Ram Berlin slrprd slrprd stefanramberlin spellched stefanram721062 stefan_ram:721062 Benutzerdefinierte Typen als Parametertypen Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd721062, slrprddef721062, PbclevtugFgrsnaEnz Erklärung, Beschreibung, Info, Information, Hinweis,

Der Urheber dieses Textes ist Stefan Ram. Alle Rechte sind vorbehalten. Diese Seite ist eine Veröffentlichung von Stefan Ram.
https://www.purl.org/stefan_ram/pub/benutzerdefinierte_parameter_c++