Typwandlungen in C++ [] (Typwandlungen in C++), Lektion, Seite 723176
https://www.purl.org/stefan_ram/pub/typwandlungen_c++ (Permalink) ist die kanonische URI dieser Seite.
Stefan Ram
C++-Kurs

Implizite und explizite Wandlungsmöglichkeiten in C++ 

Vorbemerkungen

Bei den fundamentalen Typen ist es erlaubt, ein double-Objekt mit einem int-Wert zu initialisieren, wie in »double x = 2;«. Der int-Wert wird dann zuerst in einen double-Wert gewandelt und dann in das double-Objekt geschrieben. Wir haben im Grundkurs bereits die Schreibweise »double x = 2;« mit dem Gleichheitszeichen, die Schreibweise »double x{ 2 };« mit den geschweiften Klammern und die Schreibweise »double x( 2 );« mit runden Klammern kennengelernt.

In dieser Lektion verwenden wir auch manchmal „C-Stringliterale“, dies sind Zeichenfolgen in Anführungszeichen, denen kein »s« folgt, wie beispielsweise »("abc")«. Solche Literale haben, etwas vereinfacht gesagt, den Typ »char const *«. Da jener Typ in dieser Lektion hier nur als Einheit verwendet wird, ist es zum Verständnis dieser Lektion hier nicht notwendig, die genaue Bedeutung der einzelnen Teile dieses Typs, wie beispielsweise des Sternchens »*« zu verstehen.

Typwandlungen

Bei den benutzerdefinierten Typen ist es ebenfalls möglich, einen Ausdruck eines Typs an einer Stelle zu verwenden, an der ein Ausdruck eines anderen Typs erwartet wird.

Im allgemeinen kann ein benutzerdefinierter Typ A  in einem benutzerdefinierten Typ B  gewandelt werden, wenn B  einen Konstruktor hat, der ein Argument vom Typ A  erwartet oder A  einen Wandlungsoperator enthält, der ein Ergebnis vom Typ B  hat.

Implizite Wandlungsmöglichkeiten

In bestimmten Fällen werden nur implizite Wandlungsmöglichkeiten  zur Umwandlung herangezogen. Dies sind Konstruktoren oder Wandlungsoperatoren, welche nicht ausdrücklich mit »explicit« gekennzeichnet sind. Dies soll unerwünschte versehentliche Wandlungen verhindern.

Explizite Wandlungsoperatoren

Der Typ von »::std::cout« ist »::std::ostream«. Dieser Typ enthält einen »operator bool()«, wie man in seiner Dokumentation nachlesen kann. Dadurch wird ausgedrückt, daß ein Wert dieses Typs (also beispielsweise »::std::cout«) als bool-Wert interpretiert werden kann.

Allgemein ist ein Typwandlungsoperator, der es erlaubt, einen Wert einer Klasse A  als Wert eines Typs B  zu interpretieren, in der Dokumentation der Klasse A  zu finden und heißt »operator B «.

Der Operator »operator bool()« der Klasse »::std::ostream« ist aber mit »explicit« gekennzeichnet. Das bedeutet, daß die bool-Interpretation nur in bestimmten Fällen zulässig ist.

Dokumentation

explicit operator bool() const;

Returns: !fail().

Das folgende Programm zeigt, daß explicit-Interpretationen herangezogen werden, wenn ein Initialisierungsausdruck in der Schreibweise mit runden oder geschweiften Klammern verwendet wird. Sie werden aber nicht herangezogen, wenn der Initialisierungsausdruck in der Schreibweise mit einen Gleichheitszeichen verwendet wird, weswegen die entsprechende Deklaration in dem folgenden Programm nur in einem Kommentar enthalten ist.

main.cpp

#include <iostream>
#include <ostream>

int main()

{ { bool b{ ::std::cout }; }
{ bool b( ::std::cout ); } /* Wegen "explicit" nicht moeglich:
{ bool b = ::std::cout; } */ }

Der Ausgabestrom »::std::cout« kann also in bestimmten Fällen als bool-Wert interpretiert werden. Was soll dieser Wert dann aber bedeuten? Er ist »true« genau dann, wenn der Strom als ungestört gekennzeichnet wurde. Man kann an dem Ergebnis der Interpretation also erkennen, ob der Strom störungsfrei ist.

Nicht-Explizite Wandlungsoperatoren

Derzeit ist kein Beispiel eines nicht-expliziten Wandlungsoperators aus der C++ -Standardbibliothek bekannt. Wenn man sich aber einmal vorstellt, daß »operator bool« aus der Klasse »::std::ostream« nicht mit »explicit« gekennzeichnet wäre, dann wären auch die auskommentierten Arten der Verwendung möglich. Es wären dann auch Arten der Verwendung möglich, wie sie im nächsten Abschnitt zu nicht-expliziten Konstruktoren geschildert werden.

Nicht-explizite Konstruktoren

Da der Begriff „impliziter Konstruktor“ auch anders (als ein später behandelter „implizit-erzeugter“ Konstruktor) verstanden werden kann, sollte nicht von einem „impliziten Konstruktor“ gesprochen werden, wenn ein nicht-expliziter Konstruktor gemeint ist.

Nicht nur die Einträge einer Klasse, welche die Form »operator B « haben, werden zur Interpretation eines Wertes herangezogen, sondern auch Konstruktoren.

Wenn eine Klasse B  einen Konstruktor mit einem Parameter vom Typ A  enthält und dieser keine anderen Parameter hat oder deren Angabe optional ist, dann kann jener Konstruktor herangezogen werden, um einen Wert des Typs A  als Wert der Klasse B  zu interpretieren.

Auch solche Konstruktoren können mit »explicit« gekennzeichnet werden, was dann dieselbe Bedeutung hat, wie sie schon oben für Wandlungsoperatoren beschrieben wurde.

Der folgende vereinfachte Auszug aus der Dokumentation der Klasse zeigt einen Konstruktor der Klasse »::std::string«, der einen Ausdruck vom Typ »char const *« als Parameter hat. Dieser Konstruktor ist nicht  mit »explicit« gekennzeichnet.

Dokumentation der Klasse »::std::string« nach C++ 2015, 21.4.2 (vereinfacht und übersetzt)
::std::string( char const * s );
Anlegen eines ::std::string-Exemplars mit dem Text eines Zeichenfolgenliterals.

Wie ein Typwandlungsoperator, so wird auch solch ein Konstruktor bei Bedarf herangezogen, um einen Wert eines gewünschten Typs zu erhalten. Der hier gezeigte Konstruktor erlaubt es, einen Wert eines Ausdrucks vom Typ »char *« oder »char const *« als Wert vom Typ »::std::string« zu interpretieren.

Da dieser Konstruktor nicht  mit »explicit« gekennzeichnet ist, wird er in mehr Fällen herangezogen als eine Typwandlungsmöglichkeit, die mit »explicit« gekennzeichnet ist. Beispielsweise wird er auch für Initialisierungen herangezogen, die mit einem Gleichheitszeichen geschrieben sind.

main.cpp

#include <string>

using namespace ::std::literals;

int main()
{ { ::std::string s{ "abc"s }; }
{ ::std::string s( "abc"s ); }
{ ::std::string s = "abc"s; /* <- waere nicht erlaubt bei "explicit" */ }}

Wandlungskonstruktoren

Tatsächlich wird ein Konstruktor, der ohne den Funktionsspezifizierer »explicit« deklariert wurde, als wandelnder Konstruktor  oder Wandlungskonstruktor  bezeichnet.

C++ 2015
12.3.1 Conversion by constructor [class.conv.ctor]
1 A constructor declared without the function-specifier explicit specifies a conversion from the types of its parameters to the type of its class. Such a constructor is called a converting constructor.

(Geschichtlicher Hinweis: Früher wurde einmal noch zusätzlich verlangt, daß ein Wandlungskonstruktor mit genau einem  Argument aufgerufen werden kann.)

Explizite Konstruktoren

Die folgende Dokumentation zeigt einen mit »explicit« gekennzeichneten Konstruktor.

Dokumentation der Klasse »::std::regex« nach C++ 2015 (vereinfacht und übersetzt)
explicit regex( char const * p );
Anlegen eines ::std::regex-Exemplars mit dem Text eines Zeichenfolgenliterals.

Das folgende Programm zeigt, daß der oben gezeigte explizite Konstruktor in einer Deklaration mit der Initialisierung mit runden oder geschweiften Klammern zur Interpretation eines Zeichenfolgenausdrucks verwendet werden kann. Bei der Schreibweise mit dem Gleichheitszeichen ist dies nicht möglich.

main.cpp

#include <regex>
#include <string>

using namespace ::std::literals;

int main()
{ { ::std::regex r{ "abc"s }; }
{ ::std::regex r( "abc"s ); } /* nicht erlaubt, da "explicit":
{ ::std::regex r = "abc"s; } */ }

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 stefanram723176 stefan_ram:723176 Typwandlungen in C++ Stefan Ram, Berlin, and, or, near, uni, online, slrprd, slrprdqxx, slrprddoc, slrprd723176, slrprddef723176, 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/typwandlungen_c++