Namensräume
Varianten
Aktionen

Typ

Von cppreference.com
< cpp‎ | Sprache
 
 
C++ Sprache
Allgemeine Themen
Kontrollfluss
Bedingte Ausführungsaussagen
if
Iterationsanweisungen (Schleifen)
for
Bereichs-for (C++11)
Sprunganweisungen
Funktionen
Funktionsdeklaration
Lambda-Funktionsausdruck
inline-Spezifizierer
Dynamische Ausnahmespezifikationen (bis C++17*)
noexcept-Spezifizierer (C++11)
Ausnahmen
Namensräume
Typen
Spezifizierer
const/volatile
decltype (C++11)
auto (C++11)
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Speicherdauer-Spezifizierer
Initialisierung
Ausdrücke
Alternative Darstellungen
Literale
Boolesch - Ganzzahl - Gleitkommazahl
Zeichen - String - nullptr (C++11)
Benutzerdefinierte (C++11)
Dienstprogramme
Attribute (C++11)
Typen
typedef-Deklaration
Typalias-Deklaration (C++11)
Umwandlungen
Speicherzuweisung
Klassen
Klassenspezifische Funktionseigenschaften
explicit (C++11)
static

Spezielle Member-Funktionen
Templates
Sonstiges
 
 

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:

(seit C++11)
  • 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]
  • der Typ char8_t
(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;
  • erweiterte vorzeichenbehaftete Ganzzahltypen (implementierungsabhängig);
(seit C++11)
  • Vorzeichenlose Ganzzahltypen
  • standardmäßige vorzeichenlose Ganzzahltypen: unsigned char, unsigned short, unsigned, unsigned long, unsigned long long;
  • erweiterte vorzeichenlose Ganzzahltypen (jeder entspricht einem erweiterten vorzeichenbehafteten Ganzzahltyp und umgekehrt);
(seit C++11)
  • standardmäßige Gleitkommatypen: float, double, long double und deren CV-qualifizierte Versionen;
  • erweiterte Gleitkommatypen (einschließlich CV-qualifizierter Versionen)
(seit C++23)
  • lvalue-Referenzen auf Objekttypen;
  • lvalue-Referenzen auf Funktionstypen;
  • rvalue-Referenzen auf Objekttypen;
  • rvalue-Referenzen auf Funktionstypen;
(seit C++11)
(seit C++11)
  1. 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):

(seit C++11)
  • CV-qualifizierte Versionen dieser Typen

Die folgenden Typen werden kollektiv als Implizit-Lebenszeit-Typen bezeichnet

Die folgenden Typen werden kollektiv als triviale Kopiertypen bezeichnet

Die folgenden Typen werden kollektiv als Standardlayouttypen bezeichnet

(seit C++11)

Typenhierarchiediagramm

cpp types v3.svg

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)

  • Skalartypen
  • POD-Klassen
  • Arrays solcher Typen
  • CV-qualifizierte Versionen dieser Typen
(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.
  • Ein Closure-Typ eines nicht von der Implementierung bereitgestellten Lambda-Ausdrucks.
(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, new und typeid;
  • 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;
  • in einer dynamischen Ausnahme-Spezifikation.
(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.

[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 T oder Argumenttyp T;
  • Definition eines Objekts vom Typ T;
  • Deklaration eines nicht-statischen Klassen-Datenmembers vom Typ T;
  • new-Ausdruck für ein Objekt vom Typ T oder ein Array, dessen Elementtyp T ist;
  • lvalue-zu-rvalue-Konvertierung, angewendet auf ein glvalue vom Typ T;
  • eine implizite oder explizite Konvertierung zum Typ T;
  • eine Standardkonvertierung, dynamic_cast oder static_cast zu 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, sizeof oder alignof, angewendet auf Typ T;
  • 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 N T") 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.

[bearbeiten] Externe Links

1.  Howard Hinnants C++0x Typ-Baumstruktur.