< Langage C++
fin de la boite de navigation du chapitre

Les Pointeurs

Les pointeurs servent à accéder aux données en mémoire par le biais de leur adresse. Le type pointeur est un entier non signé dont la taille dépend du type de processeur et du mode en cours. En gros, et pour simplifier, il utilise le format du "unsigned long int" actuellement en cours, où il enregistre l'adresse mémoire de la donnée à pointer.

Adresse Valeur Nom de variable
... ... ...
0x635 'P' x
... ... ...
0x7B8 0x00000635 p
... ... ...

Voici la syntaxe :

Définition
Syntaxe:
<Type>* <NomPointeur>[ = <Valeur>];

Où <Type> est le type de la donnée en mémoire, "*" signifie que l’on a affaire à un pointeur, <NomPointeur> est l'identifiant du pointeur et <Valeur> l'adresse mémoire (unsigned long int) où le pointeur doit aller chercher la donnée.


Affectation d'adresse

En C++, il est utile de récupérer l'adresse d'une variable ou d'une constante en utilisant l'opérateur "&" qui signifie "adresse de" et se place à gauche de l'identifiant.

Exemple
char x = 'A'; // création de la variable char en pile
char* p = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse de la variable en pile.
Fin de l'exemple

Comprendre : création d'une variable nommée "p" de type pointeur sur char "char*" prenant pour valeur "=" l'adresse de "&" la variable "x"

Mécanique d'Adressage

En C++, il peut être utile de copier l'adresse d'une variable pointée par un pointeur sur un autre pointeur. Cela se fait ainsi :

Exemple
char x = 'A'; // création de la variable char en pile
char* p1 = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse.
char* p2 = p1; // copie la valeur de l'adresse pointée par p1 dans le pointeur p2. (p2 == p1), (p2 == &x)
Fin de l'exemple

On n'utilise pas l'opérateur "adresse de" dans ce cas là car "p1" renvoie l'adresse de "x"

Déréférencement

En C++, il peut être utile de récupérer la valeur d'une variable pointée par un pointeur. Cela se fait ainsi :

Exemple
char x = 'A'; // création de la variable char en pile
char* p = &x; // création de la variable pointeur sur char en pile et affectation de l'adresse.
char y = *p; // Déréférencement du pointeur "p" pour obtenir la valeur pointée (y == 'A')
Fin de l'exemple

Arithmétique des pointeurs

En C++, les pointeurs ont leur propre algorithmique. L'incrémentation et la décrémentation est particulière pour ce type. En fait, l'incrémentation (ainsi que la décrémentation) se fait en multipliant la taille du type du pointeur (obtenue avec sizeof()) par la valeur que l’on veut lui ajouter/retrancher.

L'arithmétique de pointeur est un concept particulier qu’il est possible d’éviter avec les notations liées au tableau. En particulier en C++, il est intéressant de s'interdire de recourir à l’arithmétique de pointeurs.

Exemple
int a; // création de la variable int en pile (sizeof(int) == 4)
int* p = &a; // création de la variable pointeur sur int et affectation de l'adresse de a.
int* x = p++; // création de la variable pointeur sur int x (x == &a)
int* y = p; // création de la variable pointeur sur int y (y == &a + 4 octets)
int* z = ++p; // création de la variable pointeur sur int z (z == &a + 8 octets)
x = p--; // (x == &a + 8 octets)
y = p; // (y == &a + 4 octets)
z = --p; // (z == &a)
// plus explicitement
x = p; // (x == &a)
y = p + 1; // (y == &a + 4 octets)
z = p + 1; // (z == &a + 8 octets)
x = p; // (x == &a + 8 octets)
y = p - 1; // (y == &a + 4 octets)
z = p - 1; // (z == &a)
Fin de l'exemple

Ce comportement permet la création et l’utilisation des tableaux. Nous verrons cela un peu plus bas.

Lorsque les pointeurs sont créés, ils prennent la valeur d'adresse qu’il y avait à l'emplacement qu’ils occupent. C'est pour cela qu’il faut impérativement les initialiser avant de s'en servir. Dans le cas contraire on peut assister, parfois, à des comportements des plus étranges.

Le pire des cas est celui du pointeur non initialisé à qui l’on affecte une valeur. Dans certains cas rares, l’application fonctionne sur l'ordinateur de développement car la donnée que le pointeur va prendre comme adresse, correspond à une adresse valide et donc le programme se déroule normalement.

Mais après installation sur le poste client, l’application plante car la donnée en mémoire n'est plus la même et ne correspond plus à une adresse valide.

Panneau d’avertissement

Il est inacceptable d’utiliser la forme calculée des pointeurs pour accéder à des tableaux. Seule la forme entre crochets est valide. Le jour où un développeur instanciera un tableau dynamique sur un pointeur utilisé sous forme calculée, le programme plantera car le compilateur sera incapable de faire les déréférencements.

Préférez donc la forme entre crochets

Exemple
a = t[2][3];
Fin de l'exemple

à la forme calculée

Panneau d’avertissement
Début de l'exemple
Exemple
 a=*(t+2*3));
Fin de l'exemple


Les Tableaux

En C++, les tableaux permettent de mémoriser des ensembles de données de même type. Il en existe 2 sortes, les tableaux statiques et les tableaux dynamiques.

La différence entre tableaux statiques et dynamiques est que les tableaux statiques sont dans tous les cas des groupes d'octets contigus monolithiques dans la pile alors que les tableaux dynamiques multidimensionnels sont, le plus souvent, des groupes d'octets contigus disséminés en plusieurs paquets dans le tas.


Tableaux "Statiques"

Le fait qu’ils soient enregistrés en pile fait que leur taille doit être connue dès la compilation et donc être constante. En effet, pour le processeur, il serait mal vu de pouvoir redimensionner le tableau après la création d'autres variables en pile. Dans le cas de l'agrandissement, on écraserait les nouvelles variables et dans le cas de la diminution, on ferait des "TROUS" dans la pile, qui alors s'effondrerait.(Rappelez vous qu’il faut considérer la pile comme une pile d'assiettes)


On peut calculer le volume que le tableau statique occupe en mémoire, en multipliant la taille du type utilisé par le nombre d'éléments.

Ainsi un tableau tridimensionnel de 4 * 3 * 2 valeurs int, fera :

4(grilles) * 3(lignes) * 2(colonnes) * 4(Octets du type int) = 24(éléments)* 4(Octets du type int) = 96 Octets contigus en pile.


Voici la syntaxe :

Définition
Syntaxe:
<Type> <NomTableau> [<Constante1>](...)[<ConstanteN>];

ou

<Type> <NomTableau> [<Constante1>](...)[<ConstanteN>] = {{<Variable11,...,Variable1M>},(...),{<VariableN1,...,VariableNM>}};

ou

<Type> <NomTableau> [](...)[] = {{<Variable11,...,Variable1M>},(...),{<VariableN1,...,VariableNM>}};

Où <Type> est le type des éléments du tableau, <NomTableau> est le nom de la variable tableau, [](...)[] indique que c’est un tableau à N dimensions, <ConstanteN> est le nombre d'éléments, constant, de la dimension N du tableau (facultatif si on a défini une liste de valeurs), = assigne des valeurs au tableau (facultatif si <ConstanteN> est présent), {{},(...),{}} est une liste de valeurs des dimensions (il y en a autant que <ConstanteN>, facultatif si <ConstanteN> est présent), et <VariableN1,...VariableNM> sont les différentes valeurs que le tableau doit affecter aux éléments de la ligne N (il doit y en avoir autant que <ConstanteN>, facultatif si <ConstanteN> est présent).


Concrètement, voyons ce que ça donne si on reprend notre exemple :

Exemple
// Valeurs constantes
const int Grilles = 4;
const int Lignes = 3;
const int Colonnes = 2;
// Valeur variables
int deux = 2;
// Différentes syntaxes pour la création des tableaux statiques
int t1 [Grilles][Lignes][Colonnes]; // création d'un tableau d'entiers de 4 * 3 * 2 = 24 éléments non initialisés.
// Création d'un tableau d'entiers de 24 éléments initialisés.
int t2 [Grilles][Lignes][Colonnes] = {
                                            { 
                                                 {1, deux},
                                                 {3, 4},
                                                 {5, 6} 
                                            },
                                            { 
                                                 {7, 8},
                                                 {9, 10}, 
                                                 {11, 12}
                                            },
                                            { 
                                                 {13, 14}, 
                                                 {15, 16}, 
                                                 {17, 18} 
                                            }, 
                                            { 
                                                 {19, 20}, 
                                                 {21, 22}, 
                                                 {23, 24} 
                                            } 
                                       }; 
// Création d'un tableau d'entiers de 24 éléments initialisés.
int t3 [][3][2] = {
                         { 
                              {1, deux}, 
                              {3, 4}, 
                              {5, 6} 
                         }, 
                         {
                              {7, 8}, 
                              {9, 10}, 
                              {11, 12} 
                         }, 
                         { 
                              {13, 14}, 
                              {15, 16}, 
                              {17, 18} 
                         }, 
                         { 
                              {19, 20},
                              {21, 22},
                              {23, 24} 
                         } 
                    };
Fin de l'exemple

Les tableaux statiques, sont organisés par lignes. Cela signifie que lorsque l’on incrémente l'indice du tableau, on change de colonne plus rapidement que ce que l’on change de ligne.

Pour reprendre notre exemple, cela donnerait (en supposant que l'adresse de base du tableau t1 soit 0x02C0) :

Adresse Index no Élément Grille Ligne Colonne Valeur
0x02C0 t1[0][0][0] 0 0 0 0 1
0x02C4 t1[0][0][1] 1 0 0 1 2
0x02C8 t1[0][1][0] 2 0 1 0 3
0x02CC t1[0][1][1] 3 0 1 1 4
0x02D0 t1[0][2][0] 4 0 2 0 5
0x02D4 t1[0][2][1] 5 0 2 1 6
0x02D8 t1[1][0][0] 6 1 0 0 7
... ... ... ... ... ... ...
0x03A8 t1[2][2][1] 17 2 2 1 18
0x03AC t1[3][0][0] 18 3 0 0 19
0x03B0 t1[3][0][1] 19 3 0 1 20
0x03B4 t1[3][1][0] 20 3 1 0 21
0x03B8 t1[3][1][1] 21 3 1 1 22
0x03BC t1[3][2][0] 22 3 2 0 23
0x03C0 t1[3][2][1] 23 3 2 1 24

Pointeurs et Tableaux Statiques

Nous avons pu voir tout à l’heure que l'arithmétique des pointeurs permet de travailler sur plus d'une valeur voyons ce que cela donne :

Exemple
// Valeur variable
int trois = 3;
// Différentes syntaxes pour la création des tableaux statiques
int t[4] = {1, 2, trois, 4}; // Création d'un tableau d'entier de 4 éléments initialisés.
trois = 0; // trois = 0
int* pInt1 = t; // Création d'un pointeur sur entiers auquel on affecte t
int* pInt2 = &t[0]; // Création d'un pointeur sur entiers auquel on affecte l'adresse du premier élément du tableau t (pInt1 == pInt2)

int a = *(pInt1+2); // a == 3
int b = *(t+2); // b == 3
int c = pInt1[2]; // c == 3
Fin de l'exemple

Tableaux "Dynamiques"

Pour un tableau dynamique, il existe deux méthodes.

Tableaux Compacts

On peut utiliser le format des tableaux statiques multidimensionnels que l’on reproduit en tas.

Voici la syntaxe de déclaration :

Définition
Syntaxe:
<Type>* <NomVariable>[<Constante1>](...)[<ConstanteN>] = new <Type>[<Variable>][<Constante1>](...)[<ConstanteN>];

Où <Type> est le type du tableau, <NomVariable> est le nom identifiant du tableau, <Variable> est une variable entière non signée définissant la première dimension du tableau, <ConstanteN> sont des constantes entières non signées définissant les autres dimensions du tableau.

Aucun tableau dynamique n'est assignable à la déclaration. On ne peut pas en C++ assigner des valeurs à un tableau dynamique lors de sa création.

Exemple
// Valeurs constantes
const int vColonnes = 2;
const int vLignes = 3;
// Valeur variables
int vGrilles = 4;

int* vTableau[vLignes][vColonnes] = new int[vGrilles][vLignes][vColonnes]; // Création d'un tableau d'entiers de 24 éléments.

//...

delete [] vTableau;
Fin de l'exemple

Cela n’est pas très judicieux pour trois raisons :

  • La première c’est que les tailles des dimensions du tableau sont fixées définitivement (à moins de recréer le tableau complet).
  • La deuxième c’est que les différents éléments ne sont pas désolidarisables du tableau.
  • La troisième pour redimensionner le tableau il faut le recopier intégralement.

Techniquement, on peut faire mieux.

La seule raison valable qui peut amener à utiliser ces types de tableaux dynamiques est leur forme compacte. Ceci dit ils ne font réellement gagner de l'espace que sur les tableaux dont on connaît à l'avance la longueur. En effet, la lourdeur du traitement pour ajouter ou soustraire des éléments est souvent rédhibitoire.

Il ne reste donc qu'une solution techniquement valable en environnement PC : L'indirection de pointeurs multiples.

Indirection de Pointeurs

Le but du jeu est de créer un tableau de pointeurs où chaque pointeur pointe vers un autre tableau de pointeurs... (ce récursivement pour chaque dimension)... où chaque pointeur pointe vers un élément.

Définition
Syntaxe:
<Type> <NomTableau> = new <Type>[<Variable>];

Où <Type> est le type du tableau, <NomTableau> est le nom du tableau et <Variable> une variable entière non signée.

Voyons comment cela est représenté en mémoire :


Voici un exemple concret qui montre comment créer/détruire et manipuler un tableau utilisant l'indirection de pointeurs.

Exemple
#include <iostream>

using namespace std;

// Création d'un tableau de pointeurs triples d'entier.
int**** mCreerTableauDynamiquePointeursTriplesEntiers(int pGrilles, int pLignes, int pColonnes)
{
    int**** vTableau = new int***[pGrilles]; 
    // Pour chaque pointeur triple du tableau  
    for(int vIndexGrille = 0; vIndexGrille  < pGrilles; vIndexGrille ++) 
    {
        // Créer un tableau de pointeurs doubles dans vTableau[vIndexGrille].
        vTableau[vIndexGrille] = new int** [pLignes]; 
		
        // Pour chaque pointeur double du tableau vTableau[vIndexGrille].
        for(int vIndexLigne = 0; vIndexLigne < pLignes; vIndexLigne++) 
        {
            // Créer un tableau de pointeurs dans vTableau[vIndexGrille][vIndexLigne].
            vTableau[vIndexGrille][vIndexLigne] = new int* [pColonnes];
			
            // Pour chaque pointeur du tableau vTableau[vIndexGrille][vIndexLigne]
            for(int vIndexColonne = 0; vIndexColonne < pColonnes; vIndexColonne++)
            {
                // Créer un entier dans vTableau[vIndexGrille][vIndexLigne][vIndexColonne].
                vTableau[vIndexGrille][vIndexLigne][vIndexColonne] = new int;
				
                // Remplit l'entier avec son numéro d'élément
                *(vTableau[vIndexGrille][vIndexLigne][vIndexColonne]) = (vIndexGrille * pLignes * pColonnes) + (vIndexLigne * pColonnes) + vIndexColonne + 1;
            }
        }
    }
    return vTableau;
}

void mDetruireTableauDynamiquePointeursTriplesEntiers(int**** pTableau, int pGrilles, int pLignes, int pColonnes)
{
    // Pour chaque pointeur triple du tableau pTableau
    for(int vIndexGrille = 0; vIndexGrille < pGrilles; vIndexGrille++)
    {
        // Pour chaque pointeur double du tableau pTableau[vIndexGrille]
        for(int vIndexLigne = 0; vIndexLigne < pLignes; vIndexLigne++) 
        {
            // Pour chaque pointeur du tableau pTableau[vIndexGrille][vIndexLigne]
            for(int vIndexColonne = 0; vIndexColonne < pColonnes; vIndexColonne++)
            {
                // Détruire l'entier dans pTableau[vIndexGrille][vIndexLigne][vIndexColonne].
                delete pTableau[vIndexGrille][vIndexLigne][vIndexColonne];
            }
            // Détruire le tableau de pointeurs dans pTableau[vIndexGrille][vIndexLigne].
            delete [] pTableau[vIndexGrille][vIndexLigne];
        }
        // Détruire le tableau de pointeurs doubles dans pTableau[vIndexGrille].
        delete [] pTableau[vIndexGrille]; 
    }
    // Destruction du tableau de pointeurs triples d'entiers.
    delete [] pTableau;
}

void mAfficherTableau(int**** pTableau, int pGrilles, int pLignes, int pColonnes)
{
	for(int vIndexGrille = 0; vIndexGrille < pGrilles; vIndexGrille++)
    {
        cout << "Grille : " << vIndexGrille + 1 << endl;
        for(int vIndexLigne = 0; vIndexLigne < pLignes; vIndexLigne++)
        {
            cout << "    Ligne : " << vIndexLigne + 1 << endl;
            for(int vIndexColonne = 0; vIndexColonne < pColonnes; vIndexColonne++)
            {
                cout << "        Colonne : " << vIndexColonne + 1 << " = " << *pTableau[vIndexGrille][vIndexLigne][vIndexColonne] << endl; 
            }
        }
    }
	cout << endl << "Appuyez sur [Entree] pour continuer..." << endl;	
	getchar();
}

void mInverserColonnes(int**** pTableau, int pGrilles, int pLignes, int pColonnes)
{
    for(int vIndexGrille = 0; vIndexGrille < pGrilles; vIndexGrille++)
    {          
        for(int vIndexLigne = 0; vIndexLigne < pLignes; vIndexLigne++)
        {
            for(int vIndexColonne = 0; vIndexColonne < (pColonnes / 2); vIndexColonne++)
            {
                int* vTemporaire = pTableau[vIndexGrille][vIndexLigne][vIndexColonne];
                pTableau[vIndexGrille][vIndexLigne][vIndexColonne] = pTableau[vIndexGrille][vIndexLigne][(pColonnes - 1) - vIndexColonne];
                pTableau[vIndexGrille][vIndexLigne][(pColonnes - 1) - vIndexColonne] = vTemporaire;
            }
        }
    }
}

void mInverserLignes(int**** pTableau, int pGrilles, int pLignes)
{
    for(int vIndexGrille = 0; vIndexGrille < pGrilles; vIndexGrille++)
    {          
        for(int vIndexLigne = 0; vIndexLigne < (pLignes / 2); vIndexLigne++)
        {
            int** vTemporaire = pTableau[vIndexGrille][vIndexLigne];
            pTableau[vIndexGrille][vIndexLigne] = pTableau[vIndexGrille][(pLignes - 1) - vIndexLigne];
            pTableau[vIndexGrille][(pLignes - 1) - vIndexLigne] = vTemporaire;
        }
    }
}

void mInverserGrilles(int**** pTableau, int pGrilles)
{
    for(int vIndexGrille = 0; vIndexGrille < (pGrilles / 2); vIndexGrille++)
    {          
        int*** vTemporaire = pTableau[vIndexGrille];
        pTableau[vIndexGrille] = pTableau[(pGrilles - 1) - vIndexGrille];
        pTableau[(pGrilles - 1) - vIndexGrille] = vTemporaire;
    }
}

int main(int argc, char* argv[])
{
    // Valeur variables
    int vColonnes = 2;
    int vLignes = 3;
    int vGrilles = 4;

    int**** vTableau = mCreerTableauDynamiquePointeursTriplesEntiers(vGrilles, vLignes, vColonnes);
    
    cout << "Tableau a l'etat initial" << endl << endl;
	
    // Affiche le tableau
    mAfficherTableau(vTableau, vGrilles, vLignes, vColonnes);
    // Le tableau est trié du plus petit au plus grand.

    cout << "Inversion des Colonnes" << endl << endl;
	
    // Intervertit les colonnes
    mInverserColonnes(vTableau, vGrilles, vLignes, vColonnes);
    // Affiche le résultat
    mAfficherTableau(vTableau, vGrilles, vLignes, vColonnes);

    cout  << "Invertion des Lignes" << endl << endl;
	
    // Intervertit les lignes
    mInverserLignes(vTableau, vGrilles, vLignes);
    // Affiche le résultat
    mAfficherTableau(vTableau, vGrilles, vLignes, vColonnes);

    cout << "Inversion des Grilles" << endl << endl;
	
    // Intervertit les Grilles
    mInverserGrilles(vTableau, vGrilles);
    // Affiche le résultat
    mAfficherTableau(vTableau, vGrilles, vLignes, vColonnes);
    // Le tableau est trié du plus grand au plus petit.
    mDetruireTableauDynamiquePointeursTriplesEntiers(vTableau, vGrilles, vLignes, vColonnes);
    
    return 0;
}
Fin de l'exemple

Pointeurs sur Méthodes

En C++, il est possible de créer des pointeurs sur des méthodes. Cela est surtout utile pour lier les fonctions d'une bibliothèque de liens dynamiques ou, plus intéressant, pour appeler des méthodes que l’on ne connaît pas à l'avance mais qui auront un prototype que l’on a défini. Cela permet, par exemple, de créer une liste de tâches à accomplir suite à un évènement donné.

Définition
Syntaxe:
<TypeRetour> (*<NomPointeur>)(<TypeParametre><NomParametres>);

Où "<TypeRetour>" est le type de retour de la méthode à pointer, "<NomPointeur>" est le nom attribué au pointeur, "<TypeParametre>" et "<NomParametres>" sont respectivement les types et noms des paramètres de la méthode

Exemple
// Méthode
bool MaMethode(int MonParametre)
{
     return true;
}
//Pointeur correspondant à la méthode
bool (*LaMethode)(int Params);
LaMethode = MaMethode; 
// Appel de la méthode via le pointeur
bool a = LaMethode(8);
Fin de l'exemple

Remarquez bien les parenthèses autour de "*LaMethode". Si on ne les avait pas mis comme dans cet exemple :

Exemple
// Méthode
bool MaMethode(int MonParametre)
{
     return true;
}
//Pointeur correspondant à la méthode
bool *LaMethode(int Params);
LaMethode = MaMethode; 
// Appel de la méthode via le pointeur
bool a = LaMethode(8);
Fin de l'exemple


Le compilateur aurait compris "LaMethode" une méthode qui accepte un paramètre "Params" de type "int" et retourne un pointeur de type "bool";

Pointeurs sur Méthodes Encapsulées

Il est possible de créer des pointeurs sur des méthodes qui sont encapsulées dans des classes à deux conditions :

  • la méthode doit être publique,
  • la méthode doit être statique.
Exemple
//Classe
class MaClasse
{
public:
// Méthode
static bool MaMethode(int MonParametre)
{
     return true;
}
}
//Pointeur correspondant à la méthode
bool (*LaMethode)(int Params) = MaClasse::MaMethode; 
// Appel de la méthode via le pointeur
bool a = LaMethode(8);
Fin de l'exemple

Les Références

Devant la difficulté qu'avaient la plupart des programmeurs de l'époque, à gérer convenablement la mémoire avec les pointeurs, le C++ a introduit la notion de référence. Une référence est un ALIAS, un autre nom, pour une variable DÉJÀ EXISTANTE. À l'inverse du pointeur, une référence n'occupe pas de place en mémoire. Le compilateur la remplace par le nom de la variable actuellement assignée dans le code après avoir déroulé les traitements mais avant de traduire ce code en binaire.


Définition
Syntaxe:
<Type>& <NomRéférence> = <NomVariable>;

Où "<Type>" est le type de la référence "<NomRéférence>" est l'identifiant de la référence et <NomVariable> est l'identifiant de la variable que la référence doit désigner. Contrairement aux pointeurs, la référence doit impérativement être assignée dès la déclaration et il n’est pas possible de réassigner la référence à une autre variable après initialisation.


Ou plus concrètement :

Exemple
//Variable à référencer
int MaVariable = 5;
//Référence correspondant à la variable;
int& LaVariable = MaVariable; 
// Modification de la variable via la référence.
LaVariable = 8;
Fin de l'exemple

Références sur Méthodes

À l'instar du pointeur, il est possible de référencer une méthode.


Définition
Syntaxe:
<Type> (&<NomRéférence>)(<TypeParam> <NomParam>) = <NomMéthode>;

Où "<Type>" est le type de retour de la méthode à référencer, "<NomRéférence>" est l'identifiant de la référence, <TypeParam> et <NomParam> sont respectivement le type et le nom de l'image des paramètres de la méthode à référencer et <NomMéthode> est l'identifiant de la méthode que la référence doit désigner. Contrairement aux pointeurs, la référence doit impérativement être assignée dès la déclaration et il n’est pas possible de réassigner la référence à une autre méthode après initialisation.

Exemple
bool MaMethode(int MonParametre)
{
     return true;
}
//Référence correspondant à la méthode
bool (&LaMethode)(int Params) = MaMethode; 
// Appel de la méthode via la référence.
bool a = LaMethode(8);
Fin de l'exemple

Le Casting :

L'une des fonctionnalités les plus appréciées dans la manipulation des variables est l'opérateur de casting, ou de refonte, que sont les parenthèses "()".

Syntaxe:
(<Type>)[<Constante>|<Variable>]

Où <Type> est le type dans lequel la valeur <Constante> ou <Variable> doit être refondue.

En fait, on peut refondre des valeurs de types différents de manière sûre si au moins l'une de ces conditions est remplie :

  • La valeur source peut être transcodée dans le type de destination.(ex. : (char)'A'; est équivalent à (char)41; "41" est un const int)
  • Le type de la valeur source peut être approximée ou être un sous ensemble du type de la variable de destination (numérique, ex. : (double)int ou (int)double).
  • Le type de la valeur source hérite du type de la variable de destination (upcasting).
  • Le type de la valeur source est parente du type de la variable de destination (downcasting).
Panneau d’avertissement Attention : L'utilisation de l'opérateur de refonte est à utiliser avec précautions. Le compilateur ne vous avertira pas si un dépassement de capacité a lieu ou si vous faites des downcasting (refontes descendantes) avec des types de nature différente

Exemples :

Exemple de cast pour une valeur constante

Exemple
// Création d'une variable "c" de type "char" non initialisée.
char c; 

// cast de la valeur constante 0x43 (0x43 = 'C') en char. 
c = (char)0x43;
Fin de l'exemple

Autre exemple pour une variable :

Exemple
// Création d'une variable "c" de type "char" non initialisée.
char c; 
// Création d'une variable "i" de type "int" non initialisée.
int i;

// Affectation du caractère "A" à la variable c. 
c = 'A';
// cast de la valeur de la variable ('A' = 0x41 = 65) en int. 
i = (int)c;
Fin de l'exemple


Cet article est issu de Wikiversity. Le texte est sous licence Creative Commons - Attribution - Partage dans les Mêmes. Des conditions supplémentaires peuvent s'appliquer aux fichiers multimédias.