C++ Types de données

Lorsque l'on programme dans un langage de programmation, diverses variables sont nécessaires pour stocker divers types d'informations. Une variable conserve l'emplacement mémoire de la valeur qu'elle stocke. Cela signifie que lorsque vous créez une variable, un certain espace est réservé en mémoire.

Vous pouvez avoir besoin de stocker des informations de divers types de données (tels que caractère, caractère large, entier, nombre à virgule flottante, nombre à virgule flottante double, booléen, etc.). Le système d'exploitation allouera de la mémoire en fonction du type de données de la variable et décidera de ce qu'il faut stocker dans la mémoire réservée.

Types de base intégrés

C++ fournit aux programmeurs une riche variété de types de données intégrés et de types de données définis par l'utilisateur. Le tableau suivant répertorie sept types de données C++ de base :

TypeMots-clés
Type booléenbool
Type caractèrechar
entierint
Type à virgule flottantefloat
Type à virgule flottante doubledouble
Void void
Type caractère large

wchar_t

En fait, wchar_t est dérivé comme ceci :

typedef short int wchar_t;

Par conséquent, wchar_t occupe en fait le même espace que short int.

Certains types de base peuvent être modifiés avec un ou plusieurs modificateurs de type :

ModificateursDescriptionExemple
signedIndique un type signé (par défaut)signed int x = -10;
unsignedDésigne un type non signéunsigned int y = 10;
shortDésigne un type entier courtshort int z = 100;
longDésigne un type entier longlong int a = 100000;
constIndique une constante, la valeur ne peut pas être modifiéeconst int b = 5;
volatileIndique que la variable peut être modifiée de manière inattendue, ce qui empêche l'optimisation du compilateur.volatile int c = 10;
mutableIndique que les membres d'une classe peuvent êtreconstModifiés dans l'objetmutable int counter;

Le tableau suivant montre la mémoire requise pour divers types de variables lors du stockage de valeurs en mémoire, ainsi que les valeurs maximale et minimale qu'une variable de ce type peut stocker.

Remarque :Il peut y avoir des différences entre les différents systèmes ; un octet correspond à 8 bits.

Remarque :Par défaut, int, short et long sont signés.

Remarque :long int occupe 8 octets, et int occupe toujours 4 octets. Les premiers compilateurs C définissaient long int comme occupant 4 octets et int comme occupant 2 octets. Les normes C/C++ plus récentes sont compatibles avec ce paramètre d'origine.

Types de donnéesDescriptionTaille (octets)Exemple de plage/valeur
boolType booléen, représentant true ou false1trueoufalse
charType caractère, généralement utilisé pour stocker des caractères ASCII.1-128 à 127 ou 0 à 255
signed charType caractère signé1-128 à 127
unsigned charType de caractère non signé10 à 255
wchar_tType de caractère large, utilisé pour stocker des caractères Unicode.2 ou 4Dépend de la plateforme
char16_tType de caractère Unicode 16 bits (introduit en C++11)20 à 65,535
char32_tType de caractère Unicode 32 bits (introduit en C++11)40 à 4,294,967,295
shortentier court2-32,768 à 32,767
unsigned shortEntier court non signé20 à 65,535
intentier4-2,147,483,648 à 2,147,483,647
unsigned intType entier non signé40 à 4,294,967,295
longentier long4 ou 8Dépend de la plateforme
unsigned longEntier long non signé4 ou 8Dépend de la plateforme
long longEntier long long (introduit en C++11)8-9,223,372,036,854,775,808 à 9,223,372,036,854,775,807
unsigned long longEntier long long non signé (introduit en C++11)80 à 18,446,744,073,709,551,615
floatVirgule flottante simple précision4Environ ±3.4e±38 (6-7 chiffres significatifs)
doubleVirgule flottante en double précision8Environ ±1.7e±308 (15 chiffres significatifs)
long doubleVirgule flottante en précision étendue8, 12 ou 16Dépend de la plateforme

Nouveaux types ajoutés en C++11

Types de donnéesDescriptionExemple
autoDéduction automatique de typeauto x = 10;
decltypeObtenir le type d'une expressiondecltype(x) y = 20;
nullptrConstante de pointeur nulint* ptr = nullptr;
std::initializer_listType de liste d'initialisationstd::initializer_list<int> list = {1, 2, 3};
std::tupleType tuple, qui peut stocker plusieurs valeurs de types différents.std::tuple<int, float, char> t(1, 2.0, 'a');

Notez que la taille de stockage des différents types est liée à la largeur de bits du système, mais actuellement, le courant dominant est principalement constitué de systèmes 64 bits.

Ce qui suit présente les différences de taille de stockage entre les systèmes 32 bits et les systèmes 64 bits (Windows est identique) :

D'après le tableau ci-dessus, on peut voir que la taille des variables variera en fonction du compilateur et de l'ordinateur utilisés.

L'exemple suivant affichera la taille de divers types de données sur votre ordinateur.

Exemple

#include<iostream> #include <limits> using namespace std; int main() { cout << "type : \t\t" << "************taille**************"<< endl; cout << "bool : \t\t" << "Nombre d'octets occupés :" << sizeof(bool); cout << "\Valeur maximale de t :" << (numeric_limits<bool>::max)(); cout << "\t\Valeur minimale de t :" << (numeric_limits<bool>::min)() << endl; cout << "char : \t\t" << "Nombre d'octets occupés :" << sizeof(char); cout << "\Valeur maximale de t :" << (numeric_limits<char>::max)(); cout << "\t\Valeur minimale de t :" << (numeric_limits<char>::min)() << endl; cout << "signed char: \t" << "Nombre d'octets occupés :" << sizeof(signed char); cout << "\Valeur maximale de t :" << (numeric_limits<signed char>::max)(); cout << "\t\Valeur minimale de t :" << (numeric_limits<signed char>::min)() << endl; cout << "unsigned char: \t" << "Nombre d'octets occupés :" << sizeof(unsigned char); cout << "\Valeur maximale de t :" << (numeric_limits<unsigned char>::max)(); cout << "\t\Valeur minimale de t :" << (numeric_limits<unsigned char>::min)() << endl; cout << "wchar_t: \t" << "Nombre d'octets occupés :" << sizeof(wchar_t); cout << "\Valeur maximale de t :" << (numeric_limits<wchar_t>::max)(); cout << "\t\Valeur minimale de t :" << (numeric_limits<wchar_t>::min)() << endl; cout << "short : \t\t" << "Nombre d'octets occupés :" << sizeof(short); cout << "\Valeur maximale de t :" << (numeric_limits<short>::max)(); cout << "\t\Valeur minimale de t :" << (numeric_limits<short>::min)() << endl; cout << "int : \t\t" << "Nombre d'octets occupés :" << sizeof(int); cout << "\Valeur maximale de t :" << (numeric_limits<int>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<int>::min)() << endl; cout << "unsigned : \t" << "Nombre d'octets occupés :" << sizeof(unsigned); cout << "\Valeur maximale de t :" << (numeric_limits<unsigned>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<unsigned>::min)() << endl; cout << "long : \t\t" << "Nombre d'octets occupés :" << sizeof(long); cout << "\Valeur maximale de t :" << (numeric_limits<long>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<long>::min)() << endl; cout << "unsigned long : \t" << "Nombre d'octets occupés :" << sizeof(unsigned long); cout << "\Valeur maximale de t :" << (numeric_limits<unsigned long>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<unsigned long>::min)() << endl; cout << "double : \t" << "Nombre d'octets occupés :" << sizeof(double); cout << "\Valeur maximale de t :" << (numeric_limits<double>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<double>::min)() << endl; cout << "long double: \t" << "Nombre d'octets occupés :" << sizeof(long double); cout << "\Valeur maximale de t :" << (numeric_limits<long double>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<long double>::min)() << endl; cout << "float: \t\t" << "Nombre d'octets occupés :" << sizeof(float); cout << "\Valeur maximale de t :" << (numeric_limits<float>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<float>::min)() << endl; cout << "size_t: \t" << "Nombre d'octets occupés :" << sizeof(size_t); cout << "\Valeur maximale de t :" << (numeric_limits<size_t>::max)(); cout << "\Valeur minimale de t :" << (numeric_limits<size_t>::min)() << endl; cout << "string: \t" << "Nombre d'octets occupés :" << sizeof(string) << endl; // << "\tMaximum value: " << (numeric_limits<string>::max)() << "\tMinimum value: " << (numeric_limits<string>::min)() << endl; cout << "type : \t\t" << "************taille**************"<< endl; return 0; }

Cet exemple utiliseendl, ceci insérera un caractère de nouvelle ligne après chaque ligne,<<Les opérateurs sont utilisés pour transmettre plusieurs valeurs à l'écran,sizeof()L'opérateur est utilisé pour obtenir la taille de divers types de données.

Lorsque le code ci-dessus est compilé et exécuté, il produira les résultats suivants, qui peuvent varier selon l'ordinateur utilisé :

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**************

Types de données dérivés

Types de donnéesDescriptionExemple
ArrayUne collection d'éléments du même typeint arr[5] = {1, 2, 3, 4, 5};
PointerUn type qui stocke l'adresse mémoire d'une variableint* ptr = &x;
ReferenceAlias de variableint& ref = x;
FunctionType de fonction, représentant la signature d'une fonctionint func(int a, int b);
StructType de données défini par l'utilisateur, pouvant contenir plusieurs membres de types différents.struct Point { int x; int y; };
ClassType de données défini par l'utilisateur, prenant en charge l'encapsulation, l'héritage et le polymorphisme.class MyClass { ... };
UnionPlusieurs membres partagent le même bloc de mémoireunion Data { int i; float f; };
EnumUn ensemble de constantes entières défini par l'utilisateurenum Color { RED, GREEN, BLUE };

Alias de type

AliasDescriptionExemple
typedefDéfinir un alias pour un type existanttypedef int MyInt;
usingDéfinir un alias pour un type existant (introduit en C++11)using MyInt = int;

Type de la bibliothèque standard

Types de donnéesDescriptionExemple
std::stringType de chaînestd::string s = "Hello";
std::vectorTableau dynamiquestd::vector<int> v = {1, 2, 3};
std::arrayTableau de taille fixe (introduit en C++11)std::array<int, 3> a = {1, 2, 3};
std::pairUn conteneur qui stocke deux valeursstd::pair<int, float> p(1, 2.0);
std::mapConteneur de paires clé-valeurstd::map<int, std::string> m;
std::setEnsemble de valeurs uniquesstd::set<int> s = {1, 2, 3};

Déclaration typedef

Vous pouvez utilisertypedefpour donner un nouveau nom à un type existant. Voici la syntaxe pour définir un nouveau type à l'aide de typedef :

typedef type newname; 

Par exemple, l'instruction suivante indique au compilateur que feet est un autre nom pour int :

typedef int feet;

Maintenant, la déclaration suivante est parfaitement légale ; elle crée une variable entière distance :

feet distance;

Type énuméré

Le type énuméré (énumération) est un type de données dérivé en C++, qui est une collection de plusieurs constantes d'énumération définies par l'utilisateur.

Si une variable n'a que quelques valeurs possibles, elle peut être définie comme un type énuméré. L'« énumération » consiste à lister les valeurs de la variable une par une, et la valeur de la variable ne peut se situer que dans la plage des valeurs listées.

Pour créer une énumération, vous devez utiliser le mot-cléenum. La forme générale d'un type énuméré est :

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

Si l'énumération n'est pas initialisée, c'est-à-dire lorsque "= integer constant" est omis, elle commence à partir du premier identifiant.

Par exemple, le code suivant définit une énumération color, et le type de la variable c est color. Enfin, c se voit attribuer la valeur "blue".

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

Par défaut, la valeur du premier nom est 0, la valeur du deuxième nom est 1, la valeur du troisième nom est 2, et ainsi de suite. Cependant, vous pouvez également attribuer une valeur spéciale à un nom en ajoutant simplement une valeur initiale. Par exemple, dans l'énumération suivante,greenLa valeur est 5.

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

Ici,bluea une valeur de 6, car par défaut, chaque nom est supérieur de 1 au nom précédent, mais la valeur de red est toujours 0.


Conversion de type

La conversion de type est la conversion d'une valeur d'un type de données en une valeur d'un autre type de données.

Il existe quatre types de conversion de type en C++ : la conversion statique, la conversion dynamique, la conversion const et la conversion reinterpret.

Conversion statique

La conversion statique est la conversion forcée d'une valeur d'un type de données en une valeur d'un autre type de données.

La conversion statique est généralement utilisée pour les conversions entre objets de types similaires, par exemple, convertir un type int en un type float.

La conversion statique n'effectue aucune vérification de type à l'exécution, elle peut donc entraîner des erreurs d'exécution.

Exemple

int i = 10; float f = static_cast<float>(i); // Convertir statiquement le type int en type float

Cast dynamique

La conversion dynamique (dynamic_cast) est un mécanisme en C++ utilisé pour le downcasting dans une hiérarchie d'héritage.

La conversion dynamique est généralement utilisée pour convertir un pointeur ou une référence de classe de base en pointeur ou référence de classe dérivée.

Le cast dynamique effectue une vérification de type à l'exécution. Si la conversion échoue, il renvoie nullptr pour les types pointeur, et lance une exception std::bad_cast pour les types référence.

Syntaxe :

dynamic_cast<目标类型>(表达式)
  • Type cible: doit être un type pointeur ou référence.

  • Expression: le pointeur ou la référence de classe de base à convertir.

Exemple : cast dynamique de types pointeur

#include <iostream> class Base { public: virtual ~Base() = default; // La classe de base doit avoir des fonctions virtuelles }; class Derived : public Base { public: void show() { std::cout << "méthode de la classe dérivée" << std::endl; } }; int main() { Base* ptr_base = new Derived; // Le pointeur de classe de base pointe vers un objet de classe dérivée // Convertir un pointeur de classe de base en pointeur de classe dérivée Derived* ptr_derived = dynamic_cast<Derived*>(ptr_base); if (ptr_derived) { ptr_derived->show(); // Conversion réussie, appeler la méthode de la classe dérivée } else { std::cout << "Échec du transtypage dynamique !" << std::endl; } delete ptr_base; return 0; }

Sortie :

Derived class method

Exemple : transtypage dynamique de types de référence

#include <iostream>
#include <typeinfo>

class Base {
public:
    virtual ~Base() = default; // La classe de base doit avoir des fonctions virtuelles
};

class Derived : public Base {
public:
    void show() {
        std::cout << "Méthode de la classe dérivée" << std::endl;
    }
};

int main() {
    Derived derived_obj;
    Base& ref_base = derived_obj; // Référence de classe de base liée à un objet de classe dérivée

    try {
        // Convertir une référence de classe de base en référence de classe dérivée
        Derived& ref_derived = dynamic_cast<Derived&>(ref_base);
        ref_derived.show(); // Conversion réussie, appeler la méthode de la classe dérivée
    } catch (const std::bad_cast& e) {
        std::cout << "Échec du cast dynamique : " << e.what() << std::endl;
    }

    return 0;
}

Sortie :

Derived class method
FonctionnalitésType de pointeurType de référence
Valeur de retour en cas d'échec de conversionreturnnullptrLancerstd::bad_castException
Scénarios applicablesConversion descendante, vérification de type à l'exécutionConversion descendante, vérification de type à l'exécution
Surcoût de performancePlus élevéPlus élevé
Exigence de classe de baseDoit avoir des fonctions virtuellesDoit avoir des fonctions virtuelles

Conversion const

La conversion const est utilisée pour convertir un objet de type const en un objet de type non const.

La conversion const peut être utilisée pour supprimer le const ; elle ne peut pas modifier le type de l'objet.

Exemple

const int i = 10; int& r = const_cast<int⟦⟧// const, convertir const int en int&>(i); // const_cast, convert const int to int

Conversion de réinterprétation

La conversion de réinterprétation réinterprète une valeur d'un type de données comme une valeur d'un autre type de données, généralement pour des conversions entre différents types de données.

La conversion de réinterprétation n'effectue aucune vérification, ce qui peut entraîner un comportement indéfini.

Exemple

int i = 10; float f = reinterpret_cast<float&>(i); // reinterpret_cast du type int vers le type
autres extensions