Standardkonvertierungen

Die Programmiersprache C++ definiert Konvertierungen zwischen ihren grundlegenden Typen. Sie definiert auch Konvertierungen für Zeiger- und Verweistypen sowie und für abgeleitete "pointer-to-member"-Typen. Diese Konvertierungen werden als Standardkonvertierungen bezeichnet.

In diesem Abschnitt werden die folgenden Standardkonvertierungen erläutert:

  • Ganzzahlige Erweiterungen

  • Integrale Konvertierungen

  • Unverankerte Konvertierungen

  • Unverankerte und integrale Konvertierungen

  • Arithmetische Konvertierungen

  • Zeigerkonvertierungen

  • Verweiskonvertierungen

  • Konvertierungen von Zeiger in Member

    Hinweis

    Benutzerdefinierte Typen können eigene Konvertierungen festlegen. Die Konvertierung benutzerdefinierter Typen wird in Konstruktoren und Konvertierungen behandelt.

Der folgende Code bewirkt Konvertierungen (in diesen Beispiel ganzzahlige Erweiterungen):

long  long_num1, long_num2;
int   int_num;

// int_num promoted to type long prior to assignment.
long_num1 = int_num;

// int_num promoted to type long prior to multiplication.
long_num2 = int_num * long_num2;

Das Ergebnis einer Konvertierung ist nur dann ein l-Wert, wenn hierdurch ein Verweistyp erstellt wird. Beispielsweise gibt eine benutzerdefinierte Konvertierung, die als operator int&() Verweis deklariert wurde, zurück und ist ein l-Wert. Eine als operator int() Objekt deklarierte Konvertierung gibt jedoch ein Objekt zurück und ist kein l-Wert.

Ganzzahlige Erweiterungen

Objekte eines integralen Typs können in einen anderen breiteren Integraltyp konvertiert werden, d. h. einen Typ, der eine größere Gruppe von Werten darstellen kann. Diese Verbreiterungsart wird als integrale Förderung bezeichnet. Mit integraler Heraufstufung können Sie die folgenden Typen in einem Ausdruck verwenden, wo immer ein anderer integraler Typ verwendet werden kann:

  • Objekte, Literale und Konstanten des Typs char und short int

  • Enumerationstypen

  • int Bitfelder

  • Enumeratoren

C++-Werbeaktionen sind "werterhaltend", da der Wert nach der Heraufwertung garantiert mit dem Wert vor der Heraufwertung identisch ist. Bei Wertaufbewahrungsaktionen werden Objekte kürzerer integraler Typen (z. B. Bitfelder oder Objekte vom Typ char) zum Typ int heraufgestuft, wenn int der gesamte Bereich des ursprünglichen Typs dargestellt werden kann. Wenn int der vollständige Wertebereich nicht dargestellt werden kann, wird das Objekt in den Typ unsigned inthöhergestuft. Obwohl diese Strategie mit der von Standard C verwendeten Strategie identisch ist, behalten Wertkonservierungskonvertierungen die "Signiertheit" des Objekts nicht bei.

Wertneutrale Erweiterungen und vorzeichenneutrale Erweiterungen erzeugen normalerweise dieselben Ergebnisse. Sie können jedoch unterschiedliche Ergebnisse erzielen, wenn das höhergestufte Objekt angezeigt wird:

  • Ein Operand von /, , /=%, %=, <, , <=oder >>=

    Diese Operatoren benötigen Vorzeichen zum Bestimmen des Ergebnisses. Werterhaltung und Signiererhaltung erzeugen unterschiedliche Ergebnisse, wenn sie auf diese Operanden angewendet werden.

  • Der linke Operand von >> oder >>=

    Diese Operatoren behandeln signierte und nicht signierte Mengen in einem Schichtvorgang unterschiedlich. Bei signierten Mengen verteilt ein Rechtsverschiebungsvorgang das Zeichenbit in die geräumten Bitpositionen, während die leerierten Bitpositionen in nicht signierten Mengen null gefüllt sind.

  • Ein Argument für eine überladene Funktion oder den Operanden eines überladenen Operators, der von der Signiertheit des Operandentyps für den Argumentabgleich abhängt. Weitere Informationen zum Definieren überladener Operatoren finden Sie unter Überladene Operatoren.

Integrale Konvertierungen

Integralumwandlungen sind Konvertierungen zwischen integralen Typen. Die integralen Typen sind char, ( short oder short int), int, und long longlong. Diese Typen können mit signed oder , und unsigned kann als Kurzform verwendet unsigned intunsignedwerden.

Signiert für nicht signiert

Objekte aus Ganzzahltypen mit Vorzeichen können in entsprechende Typen ohne Vorzeichen konvertiert werden. Wenn diese Konvertierungen auftreten, ändert sich das tatsächliche Bitmuster nicht. Die Interpretation der Daten ändert sich jedoch. Codebeispiel:

#include <iostream>

using namespace std;
int main()
{
    short  i = -3;
    unsigned short u;

    cout << (u = i) << "\n";
}
// Output: 65533

Im vorangehenden Beispiel wird ein signed short, i, definiert und in eine negative Zahl initialisiert. Der Ausdruck (u = i) bewirkt i , dass er in eine unsigned short vor der Zuordnung ukonvertiert wird.

Nicht signiert bei signiert

Objekte aus Ganzzahltypen ohne Vorzeichen können in entsprechende Typen mit Vorzeichen konvertiert werden. Wenn sich der nicht signierte Wert jedoch außerhalb des darstellbaren Bereichs des signierten Typs befindet, hat das Ergebnis nicht den richtigen Wert, wie im folgenden Beispiel gezeigt:

#include <iostream>

using namespace std;
int main()
{
short  i;
unsigned short u = 65533;

cout << (i = u) << "\n";
}
//Output: -3

Im vorherigen Beispiel ist ein integrales unsigned short Objekt, das in eine signierte Menge konvertiert werden muss, u um den Ausdruck (i = u)auszuwerten. Da der Wert nicht ordnungsgemäß in einem signed shortDargestellten dargestellt werden kann, werden die Daten falsch interpretiert.

Gleitkommakonvertierungen

Ein Objekt eines gleitenden Typs kann sicher in einen präziseren Gleitkommatyp konvertiert werden, d. h. die Konvertierung verursacht keinen Verlust von Bedeutung. Beispielsweise sind Konvertierungen von float zu double oder von double zu long double sicher, und der Wert ist unverändert.

Ein Objekt eines unverankerten Typs kann auch in einen weniger präzisen Typ konvertiert werden, wenn es sich in einem Bereich befindet, der durch diesen Typ dargestellt werden kann. (Siehe Gleitende Grenzwerte für die Bereiche unverankerte Typen.) Wenn der ursprüngliche Wert nicht präzise dargestellt werden kann, kann er entweder in den nächsten höheren oder den nächsten niedrigeren darstellbaren Wert konvertiert werden. Das Ergebnis ist nicht definiert, wenn kein solcher Wert vorhanden ist. Betrachten Sie das folgende Beispiel:

cout << (float)1E300 << endl;

Der Maximalwert, der nach Typ float dargestellt werden kann, ist 3,402823466E38, bei dem es sich um eine wesentlich kleinere Zahl als 1E300 handelt. Daher wird die Zahl in Unendlichkeit konvertiert, und das Ergebnis ist "inf".

Konvertierungen zwischen ganzzahligem Typ und Gleitkommatyp

Bestimmte Ausdrücke können bewirken, dass Objekte vom Typ "float" in Ganzzahltypen konvertiert werden oder umgekehrt. Wenn ein Objekt des integralen Typs in einen unverankerten Typ konvertiert wird und der ursprüngliche Wert nicht exakt dargestellt werden kann, ist das Ergebnis entweder der nächste höhere oder der nächste niedrigere darstellbare Wert.

Wenn ein Objekt des unverankerten Typs in einen integralen Typ konvertiert wird, wird der Bruchteil abgeschnitten oder in Richtung Null gerundet. Eine Zahl wie 1,3 wird in 1 konvertiert, und -1.3 wird in -1 konvertiert. Wenn der abgeschnittene Wert höher als der höchste darstellbare Wert oder niedriger als der niedrigste darstellbare Wert ist, wird das Ergebnis nicht definiert.

Arithmetische Konvertierungen

Viele binäre Operatoren (die in Ausdrücken mit binären Operatoren behandelt werden) verursachen Konvertierungen von Operanden und liefern Ergebnisse auf die gleiche Weise. Die Konvertierungen, die diese Operatoren verursachen, werden als übliche arithmetische Konvertierungen bezeichnet. Arithmetische Konvertierungen von Operanden, die unterschiedliche systemeigene Typen aufweisen, werden wie in der folgenden Tabelle dargestellt. Typedef-Typen verhalten sich entsprechend ihren zugrunde liegenden systemeigenen Typen.

Bedingungen für die Typkonvertierung

Bedingungen erfüllt Konvertierung
Jeder Operand ist vom Typ long double. Ein anderer Operand wird in Typ long doublekonvertiert.
Die vorherige Bedingung ist nicht erfüllt, und beide Operanden sind vom Typ double. Ein anderer Operand wird in Typ doublekonvertiert.
Vorherige Bedingungen sind nicht erfüllt, und beide Operanden sind vom Typ float. Ein anderer Operand wird in Typ floatkonvertiert.
Vorausgehende Bedingungen nicht erfüllt (keiner der Operanden ist vom Typ „floating“). Operanden erhalten integrale Werbeaktionen wie folgt:

- Wenn ein Operand vom Typ unsigned longist, wird der andere Operand in Typ unsigned longkonvertiert.
- Wenn die vorangehende Bedingung nicht erfüllt ist und beide Operanden vom Typ long und vom anderen Typ unsigned intsind, werden beide Operanden in typkonvertiert unsigned long.
- Wenn die beiden vorangehenden Bedingungen nicht erfüllt sind und beide Operanden vom Typ sind long, wird der andere Operand in den Typ longkonvertiert.
- Wenn die vorstehenden drei Bedingungen nicht erfüllt sind und beide Operanden vom Typ sind unsigned int, wird der andere Operand in Typ unsigned intkonvertiert.
- Wenn keine der vorherigen Bedingungen erfüllt ist, werden beide Operanden in Typ intkonvertiert.

Das folgende Codebeispiel veranschaulicht die Konvertierungsregeln, die in der Tabelle beschrieben werden:

double dVal;
float fVal;
int iVal;
unsigned long ulVal;

int main() {
   // iVal converted to unsigned long
   // result of multiplication converted to double
   dVal = iVal * ulVal;

   // ulVal converted to float
   // result of addition converted to double
   dVal = ulVal + fVal;
}

Die erste Anweisung im vorangehenden Beispiel zeigt die Multiplikation von zwei ganzzahligen Typen, nämlich iVal und ulVal. Die Bedingung ist erfüllt, dass keine Operand vom unverankerten Typ ist und ein Operand vom Typ unsigned intist. Der andere Operand wird iValalso in Typ unsigned intkonvertiert. Das Ergebnis wird dann zugewiesen dVal. Die hier erfüllte Bedingung ist, dass ein Operand vom Typ doubleist, sodass das unsigned int Ergebnis der Multiplikation in Typ doublekonvertiert wird.

Die zweite Anweisung im vorherigen Beispiel zeigt das Hinzufügen eines float und eines integralen Typs: fVal und ulVal. Die ulVal Variable wird in Typ float konvertiert (dritte Bedingung in der Tabelle). Das Ergebnis der Addition wird in Typ double (zweite Bedingung in der Tabelle) konvertiert und zugewiesen dVal.

Zeigerkonvertierungen

Zeiger können bei der Zuweisung, Initialisierung, beim Vergleich und bei anderen Ausdrücken konvertiert werden.

Zeiger auf Klassen

Es gibt zwei Fälle, in denen ein Zeiger auf eine Klasse in einen Zeiger auf eine Basisklasse konvertiert werden kann.

Der erste Fall tritt auf, wenn auf die bezeichnete Basisklasse zugegriffen werden kann und die Konvertierung eindeutig ist. Weitere Informationen zu mehrdeutigen Basisklassenverweise finden Sie unter "Mehrere Basisklassen".

Ob auf eine Basisklasse zugegriffen werden kann, hängt von der Art der Vererbung bei der Ableitung ab. Betrachten Sie die Vererbung in der folgenden Abbildung:

Diagram showing an inheritance graph and base class accessibility.

Das Diagramm zeigt die Basisklasse A. Klasse B erbt von A über private geschützte öffentliche. Klasse C erbt von B über öffentliche B.

Vererbungsdiagramm zur Veranschaulichung der Barrierefreiheit der Basisklasse

Die folgende Tabelle zeigt die Zugriffsmöglichkeiten auf die Basisklassen bei der Situation, die in der Abbildung veranschaulicht wird.

Typ der Funktion Ableitung Konvertierung von

B* zu A* legal?
Externe (nicht im Klassenumfang enthaltene) Funktion Privat Nein
Protected Nein
Öffentlich Ja
B-Memberfunktion (im B-Bereich) Privat Ja
Protected Ja
Öffentlich Ja
C-Memberfunktion (im C-Bereich) Privat Nein
Protected Ja
Öffentlich Ja

Im zweiten Fall, in dem ein Zeiger auf eine Klasse in einen Zeiger auf eine Basisklasse konvertiert werden kann, wird eine explizite Typkonvertierung verwendet. Weitere Informationen zu expliziten Typkonvertierungen finden Sie unter Expliziter Typkonvertierungsoperator.

Das Ergebnis einer solchen Konvertierung ist ein Zeiger auf das Unterobjekt, den Teil des Objekts, der vollständig von der Basisklasse beschrieben wird.

Der folgende Code definiert zwei Klassen, A und B, wobei B von A abgeleitet ist. (Weitere Informationen zur Vererbung finden Sie unter Abgeleitete Klassen.) Anschließend wird ein Objekt vom Typ Bund zwei Zeiger (pA und pB) definiertbObject, die auf das Objekt verweisen.

// C2039 expected
class A
{
public:
    int AComponent;
    int AMemberFunc();
};

class B : public A
{
public:
    int BComponent;
    int BMemberFunc();
};
int main()
{
   B bObject;
   A *pA = &bObject;
   B *pB = &bObject;

   pA->AMemberFunc();   // OK in class A
   pB->AMemberFunc();   // OK: inherited from class A
   pA->BMemberFunc();   // Error: not in class A
}

Der Zeiger pA ist vom Typ A *, der als "Zeiger auf ein Objekt vom Typ A" interpretiert werden kann. Elemente von bObject (z BComponent . B. und BMemberFunc) sind für den Typ B eindeutig und können daher über pAnicht zugänglich sein. Der pA-Zeiger erlaubt nur Zugriff auf die Eigenschaften (Memberfunktionen und Daten) des Objekts, die in der Klasse A definiert sind.

Zeiger auf Funktion

Ein Zeiger auf eine Funktion kann in Typ void *konvertiert werden, wenn der Typ void * groß genug ist, um diesen Zeiger zu halten.

Zeiger auf void

Zeiger auf Typ void können in Zeiger in einen beliebigen anderen Typ konvertiert werden, jedoch nur mit einem expliziten Typ (im Gegensatz zu C). Ein Zeiger auf einen beliebigen Typ kann implizit in einen Zeiger in den Typ voidkonvertiert werden. Ein Zeiger auf ein unvollständiges Objekt eines Typs kann in einen Zeiger void (implizit) und zurück (explizit) konvertiert werden. Das Ergebnis einer solchen Konvertierung entspricht dem Wert des ursprünglichen Zeigers. Ein Objekt wird als unvollständig betrachtet, wenn es deklariert wird, aber es sind unzureichende Informationen verfügbar, um seine Größe oder Basisklasse zu ermitteln.

Ein Zeiger auf jedes Objekt, das nicht const oder volatile implizit in einen Zeiger vom Typ void *konvertiert werden kann.

const- und volatile-Zeiger

C++ stellt keine Standardkonvertierung von einem const Oder volatile Typ in einen Typ bereit, der nicht oder volatilenicht const . Allerdings kann jede Art der Konvertierung mithilfe expliziter Typumwandlungen festgelegt werden (einschließlich unsicherer Konvertierungen).

Hinweis

C++-Zeiger auf Member, mit Ausnahme von Zeigern auf statische Member, unterscheiden sich von normalen Zeigern und weisen nicht dieselben Standardkonvertierungen auf. Zeiger auf statische Member sind normale Zeiger und haben die gleichen Konvertierungen wie normale Zeiger.

NULL-Zeigerkonvertierungen

Ein integraler Konstantenausdruck, der als Null ausgewertet wird oder ein solcher Ausdruck in einen Zeigertyp umgewandelt wird, wird in einen Zeiger konvertiert, der als Nullzeiger bezeichnet wird. Dieser Zeiger vergleicht immer ungleich mit einem Zeiger auf ein beliebiges gültiges Objekt oder eine beliebige Funktion. Eine Ausnahme sind Zeiger auf basierte Objekte, die denselben Offset aufweisen und dennoch auf verschiedene Objekte zeigen können.

In C++11 sollte der Nullptrtyp dem C-Stil-Nullzeiger bevorzugt werden.

Zeiger-Ausdruck-Konvertierungen

Jeder Ausdruck mit einem Arraytyp kann in einen Zeiger des gleichen Typs konvertiert werden. Das Ergebnis der Konvertierung ist ein Zeiger auf das erste Arrayelement. Im folgenden Beispiel wird eine solche Konvertierung veranschaulicht:

char szPath[_MAX_PATH]; // Array of type char.
char *pszPath = szPath; // Equals &szPath[0].

Ein Ausdruck, der eine Funktion ergibt, die einen bestimmten Typ zurückgibt, wird in einen Zeiger auf eine Funktion konvertiert, die diesen Typ zurückgibt, ausgenommen unter folgenden Bedingungen:

  • Der Ausdruck wird als Operand für die Adresse des Operators (&) verwendet.

  • Der Ausdruck wird als Operand des Funktionsaufrufoperators verwendet.

Verweiskonvertierungen

Ein Verweis auf eine Klasse kann in einen Verweis auf eine Basisklasse in diesen Fällen konvertiert werden:

  • Auf die angegebene Basisklasse kann zugegriffen werden.

  • Die Konvertierung ist eindeutig. (Weitere Informationen zu mehrdeutigen Basisklassenverweise finden Sie unter Mehrere Basisklassen.)

Das Ergebnis der Konvertierung ist ein Zeiger auf das Unterobjekt, das die Basisklasse darstellt.

Zeiger auf Member

Zeiger auf Klassenmember können bei der Zuweisung, Initialisierung, beim Vergleich und bei anderen Ausdrücken konvertiert werden. In diesem Abschnitt werden die folgenden Konvertierungen von Zeigern in Elemente beschrieben:

Zeiger auf Basisklassenmember

Ein Zeiger auf den Member einer Basisklasse kann in einen Zeiger auf den Member einer Klasse konvertiert werden, die davon abgeleitet ist, wenn die folgenden Bedingungen erfüllt sind:

  • Auf die entgegengesetzte Konvertierung von Zeigern auf eine abgeleitete Klasse in Zeiger auf eine Basisklasse kann zugegriffen werden.

  • Die abgeleitete Klasse erbt nicht virtuell von der Basisklasse.

Wenn der linke Operand ein Zeiger auf einen Member ist, muss der rechte Operand vom Typ „pointer-to-member“ oder ein konstanter Ausdruck sein, der als 0 ausgewertet wird. Diese Zuweisung ist nur in den folgenden Fällen gültig:

  • Der rechte Operand ist ein Zeiger auf einen Member derselben Klasse wie der linke Operand.

  • Der linke Operand ist ein Zeiger auf den Member einer Klasse, die öffentlich und eindeutig von der Klasse des rechten Operanden abgeleitet wird.

Nullzeiger auf Memberkonvertierungen

Ein integraler Konstantenausdruck, der als Null ausgewertet wird, wird in einen Nullzeiger konvertiert. Dieser Zeiger vergleicht immer ungleich mit einem Zeiger auf ein beliebiges gültiges Objekt oder eine beliebige Funktion. Eine Ausnahme sind Zeiger auf basierte Objekte, die denselben Offset aufweisen und dennoch auf verschiedene Objekte zeigen können.

Der folgende Code veranschaulicht die Definition eines Zeigers auf einen Member i in Klasse A. Der Zeiger pai wird mit 0 initialisiert. Das ist der NULL-Zeiger.

class A
{
public:
int i;
};

int A::*pai = 0;

int main()
{
}

Siehe auch

C#-Programmiersprachenreferenz