C++ Datentypen

Bei der Programmierung in einer Programmiersprache werden verschiedene Variablen benötigt, um verschiedenartige Informationen zu speichern. Eine Variable behält den Speicherort des von ihr gespeicherten Werts. Das bedeutet, dass beim Erstellen einer Variablen Speicherplatz im Arbeitsspeicher reserviert wird.

Sie müssen möglicherweise Informationen verschiedener Datentypen speichern (z. B. Zeichen, Breitzeichen, Ganzzahl, Gleitkommazahl, doppelte Gleitkommazahl, Boolean usw.). Das Betriebssystem reserviert Speicher auf Grundlage des Datentyps der Variable und entscheidet, was im reservierten Speicher abgelegt wird.

Grundlegende integrierte Typen

C++ bietet Programmierern eine große Vielfalt an integrierten Datentypen und benutzerdefinierten Datentypen. Die folgende Tabelle listet sieben grundlegende C++-Datentypen auf:

TypeSchlüsselwörter
Boolescher Typbool
Zeichentypchar
integerint
Gleitkommatypfloat
Double-Gleitkommatypdouble
Void void
Breitzeichen-Typ

wchar_t

Tatsächlich wird wchar_t wie folgt abgeleitet:

typedef short int wchar_t;

Daher belegt wchar_t tatsächlich denselben Speicherplatz wie short int.

Einige grundlegende Typen können mit einem oder mehreren Typmodifikatoren geändert werden:

ModifiziererBeschreibungBeispiel
signedBezeichnet einen vorzeichenbehafteten Typ (Standard)signed int x = -10;
unsignedBezeichnet einen vorzeichenlosen Typunsigned int y = 10;
shortBezeichnet einen kurzen Ganzzahltypshort int z = 100;
longBezeichnet einen langen Ganzzahltyplong int a = 100000;
constBezeichnet eine Konstante, der Wert kann nicht geändert werdenconst int b = 5;
volatileGibt an, dass die Variable unerwartet geändert werden kann, und verbietet Compiler-Optimierung.volatile int c = 10;
mutableGibt an, dass Klassenmitgliederconstim Objekt geändert werden könnenmutable int counter;

Die folgende Tabelle zeigt den Speicherbedarf verschiedener Variablentypen beim Speichern von Werten im Speicher sowie die maximalen und minimalen Werte, die eine Variable dieses Typs speichern kann.

Hinweis:Es kann Unterschiede zwischen verschiedenen Systemen geben; ein Byte ist 8 Bits.

Hinweis:Standardmäßig sind int, short und long vorzeichenbehaftet.

Hinweis:long int ist 8 Bytes und int ist immer 4 Bytes. Frühe C-Compiler legten fest, dass long int 4 Bytes und int 2 Bytes belegt. Die neueren C/C++-Standards sind mit dieser frühen Festlegung kompatibel.

DatentypenBeschreibungGröße (Bytes)Bereich/Wert-Beispiel
boolBoolescher Typ, der true oder false repräsentiert1trueoderfalse
charZeichentyp, wird normalerweise zum Speichern von ASCII-Zeichen verwendet.1-128 bis 127 oder 0 bis 255
signed charVorzeichenbehafteter Zeichentyp1-128 bis 127
unsigned charVorzeichenloser Zeichentyp10 bis 255
wchar_tBreitzeichen-Typ, wird zum Speichern von Unicode-Zeichen verwendet.2 oder 4Plattformabhängig
char16_t16-Bit-Unicode-Zeichentyp (in C++11 eingeführt)20 bis 65,535
char32_t32-Bit-Unicode-Zeichentyp (in C++11 eingeführt)40 bis 4,294,967,295
shortKurze Ganzzahl2-32,768 bis 32,767
unsigned shortVorzeichenlose kurze Ganzzahl20 bis 65,535
intinteger4-2,147,483,648 bis 2,147,483,647
unsigned intVorzeichenloser Ganzzahltyp40 bis 4,294,967,295
longLange Ganzzahl4 oder 8Plattformabhängig
unsigned longVorzeichenlose lange Ganzzahl4 oder 8Plattformabhängig
long longLange lange Ganzzahl (in C++11 eingeführt)8-9,223,372,036,854,775,808 bis 9,223,372,036,854,775,807
unsigned long longVorzeichenlose lange lange Ganzzahl (in C++11 eingeführt)80 bis 18,446,744,073,709,551,615
floatGleitkommazahl einfacher Genauigkeit4Ungefähr ±3.4e±38 (6-7 signifikante Stellen)
doubleGleitkommazahl mit doppelter Genauigkeit8Ungefähr ±1.7e±308 (15 signifikante Stellen)
long doubleGleitkommazahl mit erweiterter Genauigkeit8, 12 oder 16Plattformabhängig

Neue Typen, die in C++11 hinzugefügt wurden

DatentypenBeschreibungBeispiel
autoAutomatische Typableitungauto x = 10;
decltypeDen Typ eines Ausdrucks ermittelndecltype(x) y = 20;
nullptrNullzeigerkonstanteint* ptr = nullptr;
std::initializer_listInitialisierungslistentypstd::initializer_list<int> list = {1, 2, 3};
std::tupleTupeltyp, der mehrere Werte unterschiedlicher Typen speichern kann.std::tuple<int, float, char> t(1, 2.0, 'a');

Beachten Sie, dass die Speichergröße verschiedener Typen von der Systembitbreite abhängt, aber derzeit hauptsächlich 64-Bit-Systeme vorherrschen.

Im Folgenden sind die Unterschiede in der Speichergröße zwischen 32-Bit-Systemen und 64-Bit-Systemen aufgeführt (für Windows gilt dasselbe):

Aus der obigen Tabelle ist ersichtlich, dass die Größe von Variablen je nach Compiler und verwendetem Computer variiert.

Das folgende Beispiel gibt die Größe verschiedener Datentypen auf Ihrem Computer aus.

Beispiel

#include<iostream> #include <limits> using namespace std; int main() { cout << "Typ: \t\t" << "************Größe**************"<< endl; cout << "bool: \t\t" << "Anzahl der belegten Bytes:" << sizeof(bool); cout << "\Maximalwert von t:" << (numeric_limits<bool>::max)(); cout << "\t\Minimalwert von t:" << (numeric_limits<bool>::min)() << endl; cout << "char: \t\t" << "Anzahl der belegten Bytes:" << sizeof(char); cout << "\Maximalwert von t:" << (numeric_limits<char>::max)(); cout << "\t\Minimalwert von t:" << (numeric_limits<char>::min)() << endl; cout << "signed char: \t" << "Anzahl der belegten Bytes:" << sizeof(signed char); cout << "\Maximalwert von t:" << (numeric_limits<signed char>::max)(); cout << "\t\Minimalwert von t:" << (numeric_limits<signed char>::min)() << endl; cout << "unsigned char: \t" << "Anzahl der belegten Bytes:" << sizeof(unsigned char); cout << "\Maximalwert von t:" << (numeric_limits<unsigned char>::max)(); cout << "\t\Minimalwert von t:" << (numeric_limits<unsigned char>::min)() << endl; cout << "wchar_t: \t" << "Anzahl der belegten Bytes:" << sizeof(wchar_t); cout << "\Maximalwert von t:" << (numeric_limits<wchar_t>::max)(); cout << "\t\Minimalwert von t:" << (numeric_limits<wchar_t>::min)() << endl; cout << "short: \t\t" << "Anzahl belegter Bytes:" << sizeof(short); cout << "\Maximalwert von t:" << (numeric_limits<short>::max)(); cout << "\t\Minimalwert von t:" << (numeric_limits<short>::min)() << endl; cout << "int: \t\t" << "Anzahl belegter Bytes:" << sizeof(int); cout << "\Maximalwert von t:" << (numeric_limits<int>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<int>::min)() << endl; cout << "unsigned: \t" << "Anzahl der belegten Bytes:" << sizeof(unsigned); cout << "\Maximalwert von t:" << (numeric_limits<unsigned>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<unsigned>::min)() << endl; cout << "long: \t\t" << "Anzahl der belegten Bytes:" << sizeof(long); cout << "\Maximalwert von t:" << (numeric_limits<long>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<long>::min)() << endl; cout << "unsigned long: \t" << "Anzahl der belegten Bytes:" << sizeof(unsigned long); cout << "\Maximalwert von t:" << (numeric_limits<unsigned long>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<unsigned long>::min)() << endl; cout << "double: \t" << "Anzahl der belegten Bytes:" << sizeof(double); cout << "\Maximalwert von t:" << (numeric_limits<double>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<double>::min)() << endl; cout << "long double: \t" << "Anzahl der belegten Bytes:" << sizeof(long double); cout << "\Maximalwert von t:" << (numeric_limits<long double>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<long double>::min)() << endl; cout << "float: \t\t" << "Anzahl der belegten Bytes:" << sizeof(float); cout << "\Maximalwert von t:" << (numeric_limits<float>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<float>::min)() << endl; cout << "size_t: \t" << "Anzahl der belegten Bytes:" << sizeof(size_t); cout << "\Maximalwert von t:" << (numeric_limits<size_t>::max)(); cout << "\Minimalwert von t:" << (numeric_limits<size_t>::min)() << endl; cout << "string: \t" << "Anzahl belegter Bytes:" << sizeof(string) << endl; // << "\tMaximalwert: " << (numeric_limits<string>::max)() << "\tMinimalwert: " << (numeric_limits<string>::min)() << endl; cout << "Typ: \t\t" << "************Größe**************"<< endl; return 0; }

Dieses Beispiel verwendetendl, dabei wird nach jeder Zeile ein Zeilenumbruchzeichen eingefügt,<<Operatoren werden verwendet, um mehrere Werte an den Bildschirm auszugeben,sizeof()Der Operator wird verwendet, um die Größe verschiedener Datentypen zu ermitteln.

Wenn der obige Code kompiliert und ausgeführt wird, erzeugt er die folgenden Ergebnisse, die je nach verwendetem Computer variieren können:

type:         ************size**************
bool:         所占字节数:1    最大值:1        最小值:0
char:         所占字节数:1    最大值:        最小值:?
signed char:     所占字节数:1    最大值:        最小值:?
unsigned char:     所占字节数:1    最大值:?        最小值:
wchar_t:     所占字节数:4    最大值:2147483647        最小值:-2147483648
short:         所占字节数:2    最大值:32767        最小值:-32768
int:         所占字节数:4    最大值:2147483647    最小值:-2147483648
unsigned:     所占字节数:4    最大值:4294967295    最小值:0
long:         所占字节数:8    最大值:9223372036854775807    最小值:-9223372036854775808
unsigned long:     所占字节数:8    最大值:18446744073709551615    最小值:0
double:     所占字节数:8    最大值:1.79769e+308    最小值:2.22507e-308
long double:     所占字节数:16    最大值:1.18973e+4932    最小值:3.3621e-4932
float:         所占字节数:4    最大值:3.40282e+38    最小值:1.17549e-38
size_t:     所占字节数:8    最大值:18446744073709551615    最小值:0
string:     所占字节数:24
type:         ************size**************

Abgeleitete Datentypen

DatentypenBeschreibungBeispiel
ArrayEine Sammlung von Elementen desselben Typsint arr[5] = {1, 2, 3, 4, 5};
PointerEin Typ, der die Speicheradresse einer Variablen speichertint* ptr = &x;
ReferenceVariablen-Aliasint& ref = x;
FunctionFunktionstyp, der die Signatur einer Funktion darstelltint func(int a, int b);
StructBenutzerdefinierter Datentyp, der mehrere Member unterschiedlicher Typen enthalten kann.struct Point { int x; int y; };
ClassBenutzerdefinierter Datentyp, der Kapselung, Vererbung und Polymorphie unterstützt.class MyClass { ... };
UnionMehrere Member teilen sich denselben Speicherblockunion Data { int i; float f; };
EnumEin benutzerdefinierter Satz von Integer-Konstantenenum Color { RED, GREEN, BLUE };

Typalias

AliasBeschreibungBeispiel
typedefAlias für einen vorhandenen Typ definierentypedef int MyInt;
usingAlias für einen vorhandenen Typ definieren (in C++11 eingeführt)using MyInt = int;

Standardbibliothekstyp

DatentypenBeschreibungBeispiel
std::stringString-Typstd::string s = "Hello";
std::vectorDynamisches Arraystd::vector<int> v = {1, 2, 3};
std::arrayArray mit fester Größe (in C++11 eingeführt)std::array<int, 3> a = {1, 2, 3};
std::pairEin Container, der zwei Werte speichertstd::pair<int, float> p(1, 2.0);
std::mapContainer für Schlüssel-Wert-Paarestd::map<int, std::string> m;
std::setMenge eindeutiger Wertestd::set<int> s = {1, 2, 3};

typedef-Deklaration

Sie könnentypedefverwenden, um einem vorhandenen Typ einen neuen Namen zu geben. Das Folgende ist die Syntax zum Definieren eines neuen Typs mit typedef:

typedef type newname; 

Zum Beispiel teilt die folgende Anweisung dem Compiler mit, dass feet ein anderer Name für int ist:

typedef int feet;

Nun ist die folgende Deklaration vollkommen zulässig; sie erzeugt eine Ganzzahlvariable distance:

feet distance;

Aufzählungstyp

Der Aufzählungstyp (Enumeration) ist ein abgeleiteter Datentyp in C++, der eine Sammlung mehrerer vom Benutzer definierter Aufzählungskonstanten ist.

Wenn eine Variable nur wenige mögliche Werte hat, kann sie als Aufzählungstyp definiert werden. Die sogenannte "Aufzählung" bedeutet, die Werte der Variablen einzeln aufzulisten, und der Wert der Variablen kann nur innerhalb des Bereichs der aufgelisteten Werte liegen.

Um ein enum zu erstellen, müssen Sie das Schlüsselwortenumverwenden. Die allgemeine Form eines enum-Typs ist:

enum 枚举名{ 
     标识符[=整型常数], 
     标识符[=整型常数], 
... 
    标识符[=整型常数]
} 枚举变量;
    

Wenn die Enumeration nicht initialisiert wird, d. h., wenn "= integer constant" weggelassen wird, beginnt sie beim ersten Bezeichner.

Zum Beispiel definiert der folgende Code eine Enumeration namens color, und der Typ der Variablen c ist color. Schließlich wird c der Wert "blue" zugewiesen.

enum color { red, green, blue } c;
c = blue;

Standardmäßig ist der Wert des ersten Namens 0, der Wert des zweiten Namens 1, der Wert des dritten Namens 2 und so weiter. Sie können einem Namen jedoch auch einen speziellen Wert zuweisen, indem Sie einfach einen Anfangswert hinzufügen. Zum Beispiel in der folgenden Enumeration,greenDer Wert ist 5.

enum color { red, green=5, blue };

Hier,bluehat einen Wert von 6, weil standardmäßig jeder Name um 1 größer ist als der Name davor, aber der Wert von red ist immer noch 0.


Typumwandlung

Typumwandlung ist die Umwandlung eines Werts eines Datentyps in einen Wert eines anderen Datentyps.

In C++ gibt es vier Arten der Typumwandlung: statische Umwandlung, dynamische Umwandlung, const-Umwandlung und reinterpret-Umwandlung.

Statischer Cast

Statische Umwandlung ist die erzwungene Umwandlung eines Werts eines Datentyps in einen Wert eines anderen Datentyps.

Statische Umwandlung wird normalerweise für Umwandlungen zwischen Objekten ähnlicher Typen verwendet, zum Beispiel die Umwandlung eines int-Typs in einen float-Typ.

Statischer Cast führt keine Laufzeit-Typprüfung durch, sodass er zu Laufzeitfehlern führen kann.

Beispiel

int i = 10; float f = static_cast<float>(i); // int-Typ statisch in float-Typ umwandeln

Dynamische Umwandlung

Dynamische Umwandlung (dynamic_cast) ist ein Mechanismus in C++, der für Downcasting in einer Vererbungshierarchie verwendet wird.

Dynamische Umwandlung wird normalerweise verwendet, um einen Zeiger oder Verweis auf eine Basisklasse in einen Zeiger oder Verweis auf eine abgeleitete Klasse umzuwandeln.

Dynamische Umwandlung führt zur Laufzeit eine Typprüfung durch. Wenn die Umwandlung fehlschlägt, gibt sie für Zeigertypen nullptr zurück und löst für Referenztypen eine std::bad_cast-Ausnahme aus.

Syntax:

dynamic_cast<目标类型>(表达式)
  • Zieltyp: Muss ein Zeiger- oder Referenztyp sein.

  • Ausdruck: Der Zeiger oder Verweis auf die Basisklasse, der umgewandelt werden muss.

Beispiel: Dynamische Umwandlung von Zeigertypen

#include <iostream> class Base { public: virtual ~Base() = default; // Die Basisklasse muss virtuelle Funktionen haben }; class Derived : public Base { public: void show() { std::cout << "Methode der abgeleiteten Klasse" << std::endl; } }; int main() { Base* ptr_base = new Derived; // Basisklassenzeiger zeigt auf Objekt der abgeleiteten Klasse // Basisklassenzeiger in Zeiger auf abgeleitete Klasse umwandeln Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base); if (ptr_derived) { ptr_derived->show(); // Umwandlung erfolgreich, Methode der abgeleiteten Klasse aufrufen } else { std::cout << "Dynamischer Cast fehlgeschlagen!" << std::endl; } delete ptr_base; return 0; }

Ausgabe:

Derived class method

Beispiel: Dynamischer Cast von Referenztypen

#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual ~Base() = default; // Die Basisklasse muss virtuelle Funktionen haben
};

class Derived : public Base {
public:
    void show() {
        std::cout << "Methode der abgeleiteten Klasse" << std::endl;
    }
};

int main() {
    Derived derived_obj;
    Base& ref_base = derived_obj; // Basisklassenreferenz an Objekt der abgeleiteten Klasse gebunden

    try {
        // Basisklassenreferenz in Referenz der abgeleiteten Klasse umwandeln
        Derived& ref_derived = dynamic_cast<Derived&>(ref_base);
        ref_derived.show(); // Konvertierung erfolgreich, Methode der abgeleiteten Klasse aufrufen
    } catch (const std::bad_cast& e) {
        std::cout << "Dynamischer Cast fehlgeschlagen: " << e.what() << std::endl;
    }

    return 0;
}

Ausgabe:

Derived class method
FunktionenZeigertypReferenztyp
Rückgabewert bei fehlgeschlagener KonvertierungreturnnullptrAuslösenstd::bad_castAusnahme
Anwendbare SzenarienDowncasting, Laufzeit-TypüberprüfungDowncasting, Laufzeit-Typüberprüfung
Performance-OverheadHöherHöher
Anforderung an die BasisklasseMuss virtuelle Funktionen habenMuss virtuelle Funktionen haben

Const-Cast

Die Const-Konvertierung wird verwendet, um ein Objekt vom Typ const in ein Objekt vom Typ non-const umzuwandeln.

Eine const-Konvertierung kann nur verwendet werden, um das const-Attribut zu entfernen; sie kann den Typ des Objekts nicht ändern.

Beispiel

const int i = 10; int& r = const_cast<int&>(i); // const_cast, const int in int umwandeln

Reinterpret-Cast

Die Reinterpret-Konvertierung interpretiert einen Wert eines Datentyps als Wert eines anderen Datentyps neu; sie wird normalerweise für Konvertierungen zwischen verschiedenen Datentypen verwendet.

Die Reinterpret-Konvertierung führt keine Typprüfung durch, was zu undefiniertem Verhalten führen kann.

Beispiel

int i = 10; float f = reinterpret_cast<float&>(i); // reinterpret_cast: int-Typ in float-Typ umwandeln
Weitere Erweiterungen