Typ
Objekte, Referenzen, Funktionen, einschließlich Funktionstemplate-Spezialisierungen, und Ausdrücke haben eine Eigenschaft namens Typ, die sowohl die für diese Entitäten zulässigen Operationen einschränkt als auch der sonst generischen Bitsequenzen eine semantische Bedeutung verleiht.
Inhalt |
[bearbeiten] Typklassifizierung
Das C++-Typsystem besteht aus folgenden Typen:
- Basistypen (siehe auch std::is_fundamental)
- der Typ void (siehe auch std::is_void);
|
(seit C++11) |
- arithmetische Typen (siehe auch std::is_arithmetic)
- Ganzzahltypen (einschließlich CV-qualifizierter Versionen, siehe auch std::is_integral, ein Synonym für Ganzzahltyp ist Integer-Typ)
- der Typ bool;
- Zeichen-Typen
- enge Zeichen-Typen
- gewöhnliche Zeichen-Typen: char, signed char, unsigned char[1]
|
(seit C++20) |
- weite Zeichen-Typen: char16_t, char32_t, (seit C++11)wchar_t;
- Vorzeichenbehaftete Ganzzahltypen
- standardmäßige vorzeichenbehaftete Ganzzahltypen: signed char, short, int, long, long long;
|
(seit C++11) |
- Vorzeichenlose Ganzzahltypen
- standardmäßige vorzeichenlose Ganzzahltypen: unsigned char, unsigned short, unsigned, unsigned long, unsigned long long;
|
(seit C++11) |
- Gleitkommatypen (siehe auch std::is_floating_point)
- standardmäßige Gleitkommatypen: float, double, long double und deren CV-qualifizierte Versionen;
|
(seit C++23) |
- zusammengesetzte Typen (siehe auch std::is_compound)
- Referenztypen (siehe auch std::is_reference)
- lvalue-Referenztypen (siehe auch std::is_lvalue_reference)
- lvalue-Referenzen auf Objekttypen;
- lvalue-Referenzen auf Funktionstypen;
|
(seit C++11) |
- Zeigertypen (siehe auch std::is_pointer)
- Zeiger-auf-Mitglied-Typen (siehe auch std::is_member_pointer)
- Zeiger-auf-Datenmitglied-Typen (siehe auch std::is_member_object_pointer);
- Zeiger-auf-Mitgliedsfunktion-Typen (siehe auch std::is_member_function_pointer);
- Arraytypen (siehe auch std::is_array);
- Funktionstypen (siehe auch std::is_function);
- Aufzählungstypen (siehe auch std::is_enum);
|
(seit C++11) |
-
- Nicht-Union-Typen (siehe auch std::is_class);
- Union-Typen (siehe auch std::is_union).
- ↑ signed char und unsigned char sind enge Zeichen-Typen, aber sie sind keine Zeichen-Typen. Anders ausgedrückt, die Menge der engen Zeichen-Typen ist keine Teilmenge der Menge der Zeichen-Typen.
Für jeden nicht-CV-qualifizierten Typ außer Referenz und Funktion unterstützt das Typsystem drei zusätzliche CV-qualifizierte Versionen dieses Typs (const, volatile und const volatile).
[bearbeiten] Andere Kategorien
Ein Objekttyp (siehe auch std::is_object) ist ein (möglicherweise CV-qualifizierter) Typ, der kein Funktionstyp, keine Referenz und kein (möglicherweise CV-qualifiziertes) void ist.
Die folgenden Typen werden kollektiv als Skalartypen bezeichnet (siehe auch std::is_scalar):
- arithmetische Typen
- Aufzählungstypen
- Zeigertypen
- Zeiger-auf-Mitglied-Typen
| (seit C++11) |
- CV-qualifizierte Versionen dieser Typen
Die folgenden Typen werden kollektiv als Implizit-Lebenszeit-Typen bezeichnet
- Skalartypen
- implizit-lebenszeitbehaftete Klassentypen
- Arraytypen
- CV-qualifizierte Versionen dieser Typen
|
Die folgenden Typen werden kollektiv als triviale Kopiertypen bezeichnet
Die folgenden Typen werden kollektiv als Standardlayouttypen bezeichnet
|
(seit C++11) |
| Typenhierarchiediagramm |
|---|
|
Hinweis: Elemente des SVG-Bildes sind anklickbar, aber Sie müssen das Diagramm zuerst in einem neuen Browser-Tab öffnen. |
[bearbeiten] Veraltete Kategorien
|
Die folgenden Typen werden kollektiv als POD-Typen bezeichnet (siehe auch std::is_pod)
|
(veraltet in C++20) |
|
Die folgenden Typen werden kollektiv als triviale Typen bezeichnet (siehe auch std::is_trivial)
|
(seit C++11) (veraltet in C++26) |
[bearbeiten] Programmasspezifischer Typ
Eine programmasspezifische Spezialisierung ist eine explizite Spezialisierung oder partielle Spezialisierung, die nicht Teil der C++ Standardbibliothek ist und nicht von der Implementierung definiert wurde.
Ein programmasspezifischer Typ ist einer der folgenden Typen:
- Ein nicht-Closure(seit C++11) Klassentyp oder Aufzählungstyp, der nicht Teil der C++-Standardbibliothek ist und nicht von der Implementierung definiert wurde.
|
(seit C++11) |
- Eine Instanziierung einer programmasspezifischen Spezialisierung.
[bearbeiten] Typbenennung
Ein Name kann durch folgende Mittel zu einem Typ deklariert werden:
- Klassendeklaration;
- Union-Deklaration;
- Enum-Deklaration;
- Typedef-Deklaration;
- Typalias-Deklaration.
Typen, die keine Namen haben, müssen oft in C++-Programmen referenziert werden; die Syntax dafür ist bekannt als type-id. Die Syntax des type-id, das den Typ T benennt, ist genau die Syntax einer Deklaration einer Variablen oder Funktion vom Typ T, wobei die Kennung weggelassen wird, außer dass die decl-specifier-seq der Grammatik der Deklaration auf type-specifier-seq beschränkt ist und dass neue Typen nur definiert werden dürfen, wenn das type-id auf der rechten Seite einer Nicht-Template-Typalias-Deklaration erscheint.
int* p; // declaration of a pointer to int static_cast<int*>(p); // type-id is "int*" int a[3]; // declaration of an array of 3 int new int[3]; // type-id is "int[3]" (called new-type-id) int (*(*x[2])())[3]; // declaration of an array of 2 pointers to functions // returning pointer to array of 3 int new (int (*(*[2])())[3]); // type-id is "int (*(*[2])())[3]" void f(int); // declaration of a function taking int and returning void std::function<void(int)> x = f; // type template parameter is a type-id "void(int)" std::function<auto(int) -> void> y = f; // same std::vector<int> v; // declaration of a vector of int sizeof(std::vector<int>); // type-id is "std::vector<int>" struct { int x; } b; // creates a new type and declares an object b of that type sizeof(struct { int x; }); // error: cannot define new types in a sizeof expression using t = struct { int x; }; // creates a new type and declares t as an alias of that type sizeof(static int); // error: storage class specifiers not part of type-specifier-seq std::function<inline void(int)> f; // error: neither are function specifiers
Der declarator-Teil der Deklarationsgrammatik, bei dem der Name entfernt wurde, wird als abstract-declarator bezeichnet.
Type-id kann in folgenden Situationen verwendet werden:
- zur Angabe des Zieltyps in Cast-Ausdrücken;
- als Argumente für
sizeof,alignof,alignas,newundtypeid; - auf der rechten Seite einer Typalias-Deklaration;
- als nachfolgender Rückgabetyp einer Funktionsdeklaration;
- als Standardargument eines Template-Typparameters;
- als Template-Argument für einen Template-Typparameter;
|
(bis C++17) |
Type-id kann mit einigen Modifikationen in folgenden Situationen verwendet werden:
- in der Parameterliste einer Funktion (wenn der Parametername weggelassen wird), verwendet type-id decl-specifier-seq anstelle von type-specifier-seq (insbesondere sind einige Speicherklassenspezifizierer erlaubt);
- im Namen einer Benutzerdefinierten Konvertierungsfunktion darf der abstrakte Deklarator keine Funktions- oder Array-Operatoren enthalten.
| Dieser Abschnitt ist unvollständig Grund: 8.2[dcl.ambig.res], falls dies kompakt zusammengefasst werden kann. |
| Dieser Abschnitt ist unvollständig Grund: Verweis auf decltype und auto. |
[bearbeiten] Elaborierter Typspezifizierer
Elaborierte Typspezifizierer können verwendet werden, um auf einen zuvor deklarierten Klassennamen (Klasse, Struktur oder Union) oder auf einen zuvor deklarierten Enum-Namen zu verweisen, selbst wenn der Name durch eine Nicht-Typ-Deklaration verdeckt wurde. Sie können auch verwendet werden, um neue Klassennamen zu deklarieren.
Siehe elaborierter Typspezifizierer für Details.
[bearbeiten] Statischer Typ
Der Typ eines Ausdrucks, der sich aus der Compile-Zeit-Analyse des Programms ergibt, wird als statischer Typ des Ausdrucks bezeichnet. Der statische Typ ändert sich nicht während der Ausführung des Programms.
[bearbeiten] Dynamischer Typ
Wenn ein glvalue-Ausdruck auf ein polymorphes Objekt verweist, ist der Typ seines am weitesten abgeleiteten Objekts der dynamische Typ.
// given struct B { virtual ~B() {} }; // polymorphic type struct D : B {}; // polymorphic type D d; // most-derived object B* ptr = &d; // the static type of (*ptr) is B // the dynamic type of (*ptr) is D
Für prvalue-Ausdrücke ist der dynamische Typ immer derselbe wie der statische Typ.
[bearbeiten] Unvollständiger Typ
Die folgenden Typen sind unvollständige Typen:
- der Typ void (möglicherweise CV-qualifiziert);
- unvollständig definierte Objekttypen:
- Klassentyp, der deklariert (z. B. durch Vorwärtsdeklaration), aber nicht definiert wurde;
- Array unbekannter Größe;
- Array von Elementen eines unvollständigen Typs;
- Aufzählungstyp vom Zeitpunkt der Deklaration bis zu dem Zeitpunkt, an dem sein zugrunde liegender Typ bestimmt ist.
Alle anderen Typen sind vollständig.
Jeder der folgenden Kontexte erfordert, dass der Typ T vollständig ist:
- Definition oder Aufruf einer Funktion mit Rückgabetyp
Toder ArgumenttypT; - Definition eines Objekts vom Typ
T; - Deklaration eines nicht-statischen Klassen-Datenmembers vom Typ
T; -
new-Ausdruck für ein Objekt vom TypToder ein Array, dessen ElementtypTist; - lvalue-zu-rvalue-Konvertierung, angewendet auf ein glvalue vom Typ
T; - eine implizite oder explizite Konvertierung zum Typ
T; - eine Standardkonvertierung,
dynamic_castoderstatic_castzu Typ T* oder T&, außer bei der Konvertierung vom Nullzeiger-Konstanten oder von einem Zeiger auf ein möglicherweise CV-qualifiziertes void; - Klassenmember-Zugriffsoperator, angewendet auf einen Ausdruck vom Typ
T; - Operator
typeid,sizeofoderalignof, angewendet auf TypT; - arithmetischer Operator, angewendet auf einen Zeiger auf
T; - Definition einer Klasse mit Basisklasse
T; - Zuweisung an ein lvalue vom Typ
T; - ein Handler vom Typ
T, T& oder T*.
(Im Allgemeinen, wenn die Größe und das Layout von T bekannt sein müssen.)
Wenn eine dieser Situationen in einer Translation Unit auftritt, muss die Definition des Typs in derselben Translation Unit erscheinen. Andernfalls ist dies nicht erforderlich.
Ein unvollständig definierter Objekttyp kann vervollständigt werden.
- Ein Klassentyp (z. B. class X) kann an einem Punkt in einer Translation Unit als unvollständig betrachtet werden und später als vollständig; der Typ class X ist an beiden Punkten derselbe Typ.
struct X; // declaration of X, no definition provided yet extern X* xp; // xp is a pointer to an incomplete type: // the definition of X is not reachable void foo() { xp++; // ill-formed: X is incomplete } struct X { int i; }; // definition of X X x; // OK: the definition of X is reachable void bar() { xp = &x; // OK: type is “pointer to X” xp++; // OK: X is complete }
- Der deklarierte Typ eines Array-Objekts kann ein Array eines unvollständigen Klassentyps sein und daher unvollständig sein; wenn der Klassentyp später in der Translation Unit vervollständigt wird, wird der Array-Typ vollständig; der Array-Typ ist an diesen beiden Punkten derselbe Typ.
- Der deklarierte Typ eines Array-Objekts kann ein Array unbekannter Größe sein und daher an einem Punkt in einer Translation Unit unvollständig und später vollständig sein; die Array-Typen an diesen beiden Punkten ("Array unbekannter Größe von
T" und "Array von NT") sind unterschiedliche Typen.
Der Typ eines Zeigers oder einer Referenz auf ein Array unbekannter Größe verweist permanent auf einen unvollständigen Typ. Ein Array unbekannter Größe, das durch eine typedef-Deklaration benannt wird, verweist permanent auf einen unvollständigen Typ. In beiden Fällen kann der Array-Typ nicht vervollständigt werden.
extern int arr[]; // the type of arr is incomplete typedef int UNKA[]; // UNKA is an incomplete type UNKA* arrp; // arrp is a pointer to an incomplete type UNKA** arrpp; void foo() { arrp++; // error: UNKA is an incomplete type arrpp++; // OK: sizeof UNKA* is known } int arr[10]; // now the type of arr is complete void bar() { arrp = &arr; // OK: qualification conversion (since C++20) arrp++; // error: UNKA cannot be completed }
[bearbeiten] Fehlerberichte
Die folgenden Verhaltensändernden Fehlerberichte wurden rückwirkend auf zuvor veröffentlichte C++-Standards angewendet.
| DR | angewendet auf | Verhalten wie veröffentlicht | Korrigiertes Verhalten |
|---|---|---|---|
| CWG 328 | C++98 | Klassenmember von unvollständigem Typ wurden nicht verboten. Wenn kein Objekt vom Klassentyp jemals erstellt wurde. |
nicht-statische Klassen-Datenmember müssen vollständig sein. |
| CWG 977 | C++98 | Der Zeitpunkt, zu dem ein Aufzählungstyp in seiner Definition vollständig wird, war unklar. |
Der Typ ist vollständig, sobald der zugrunde liegende Typ bestimmt ist. |
| CWG 1362 | C++98 | Benutzerdefinierte Konvertierungen zu Typ T* oder T& erforderten, dass T vollständig ist. |
nicht erforderlich. |
| CWG 2006 | C++98 | CV-qualifizierte void-Typen waren Objekttypen und vollständige Typen. | von beiden Kategorien ausgeschlossen. |
| CWG 2448 | C++98 | Nur CV-unqualifizierte Typen konnten Ganzzahl- und Gleitkommatypen sein. | erlaubt CV-qualifizierte Typen. |
| CWG 2630 | C++98 | Es war unklar, ob eine Klasse außerhalb der Translation Unit, in der die Definition der Klasse erscheint, als vollständig betrachtet wird. |
Die Klasse ist vollständig, wenn ihre Definition in diesem Fall erreichbar ist. |
| CWG 2643 | C++98 | Der Typ eines Zeigers auf ein Array unbekannter Größe konnte nicht vervollständigt werden (obwohl er bereits vollständig ist). |
Der darauf zeigende Array-Typ kann nicht vervollständigt werden. |
| LWG 2139 | C++98 | Die Bedeutung von "benutzerdefinierter Typ" war unklar. | definiert und verwendet stattdessen "programm- definierter Typ". |
| LWG 3119 | C++11 | Es war unklar, ob Closure-Typen programmasspezifische Typen sind. | wurde klargestellt |
[bearbeiten] Referenzen
- C++23 Standard (ISO/IEC 14882:2024)
- 6.8.2 Fundamentale Typen [basic.fundamental]
- C++20 Standard (ISO/IEC 14882:2020)
- 6.8.2 Fundamentale Typen [basic.fundamental]
- C++17 Standard (ISO/IEC 14882:2017)
- 6.9.1 Fundamentale Typen [basic.fundamental]
- C++14 Standard (ISO/IEC 14882:2014)
- 3.9.1 Fundamentale Typen [basic.fundamental]
- C++11 Standard (ISO/IEC 14882:2011)
- 3.9.1 Fundamentale Typen [basic.fundamental]
- C++98 Standard (ISO/IEC 14882:1998)
- 3.9.1 Fundamentale Typen [basic.fundamental]
[bearbeiten] Siehe auch
| Typmerkmale | Compile-Zeit-Template-basierte Schnittstellen zur Abfrage von Typ-Eigenschaften. |
| C-Dokumentation für Typ
| |
[bearbeiten] Externe Links
| 1. | Howard Hinnants C++0x Typ-Baumstruktur. |