Passage par pointeur sur méthode statique

Le
TSalm
Bonjour,

Petite questions technique : je ne comprends pas pourquoi, dans ce code
"t2" est NULL.
C'est du code VC++ mais j'imagine que le problème sera le même avec un
autre compilateur

D'avance merci pour votre aide.
-TSalm


/* -- CODE -- */
#include "stdafx.h"

#include <iostream>

class Test
{
private:
Test() {}
virtual ~Test(){}

public:
static Test* Factory()
{
return new Test;
}

static void Factory2(Test* t)
{
t = new Test;
}
};

int _tmain(int argc, _TCHAR* argv[])
{
using namespace std;

Test* t1 = NULL;
t1 = Test::Factory();
cout << t1 << endl;

Test* t2 = NULL;
Test::Factory2(t2);
cout << t2 << endl;

getchar();

return 0;
}
/* -- */
Vidéos High-Tech et Jeu Vidéo
Téléchargements
Vos réponses
Gagnez chaque mois un abonnement Premium avec GNT : Inscrivez-vous !
Trier par : date / pertinence
Alain Ketterlin
Le #24427691
TSalm
static void Factory2(Test* t)
{
t = new Test;
}



Ici t est un paramètre de Factory2, c'est donc essentiellement une
variable locale. Tu peux la modifier comme tu veux, mais tu es dans un
bac à sable (le contexte d'exécution de Factory2, qui disparaà ®t à la fin
de l'appel).

Test* t2 = NULL;
Test::Factory2(t2);
cout << t2 << endl;



Ici tu appelles Factory2 en lui passant la *valeur* de t2 (qui donne sa
valeur à t dans le corps de Factory2).

Tu n'as fait que passer des valeurs de pointeurs (tu as "recopié" t2
dans t, d'une certaine façon).

Ce que tu voudrais, c'est que Factory2 affecte une valeur dans t2. Mais
pour cela il faut que Factory ait l'adresse de t2 (t2 est une variable
locale de main). Il y a deux solutions :

- la version "old school" pour les nostalgiques de C (dont moi) :

static void Factory2(Test * * t ) // un pointeur vers un pointeur
{
*t = new Test;
}
...
Test::Factory2(&t2); // on ne passe pas la valeur de t2,
// mais l'adresse de t2
// (en fait la valeur de l'adresse de t2)

- la version ultra-moderne :

static void Factory2(Test * & t) // une référence vers un point eur
{
t = new Test;
}
...
Test::Factory2(t2); // comme Factory2 prend une référence, c'est
// bien l'adresse qui est passée, pas la valeur

Dans les deux cas, on passe à Factory2 une "adresse", qui lui permet de
modifier la variable dont on a passé l'adresse. C'est moins frappant
dans le second, plus visible dans le premier cas.

Oui, ça fait deux niveaux d'indirection (on passe l'adresse d'un
pointeur). Si tu trouves ça compliqué, remplace "Test *" (Test su ivi
d'une étoile) par pointeur_t.

-- Alain.

P/S: si tu veux un conseil : ne passe pas à autre chose avant d'avoir
compris ça. C'est fondamental en C++. Et dans des tas d'autres langage s,
même quand ils ne parlent pas de pointeurs.
TSalm
Le #24430281
static void Factory2(Test* t)
{
t = new Test;
}



Ici t est un paramètre de Factory2, c'est donc essentiellement une
variable locale. Tu peux la modifier comme tu veux, mais tu es dans un
bac à sable (le contexte d'exécution de Factory2, qui disparaît à la fin
de l'appel).

Test* t2 = NULL;
Test::Factory2(t2);
cout << t2 << endl;



Ici tu appelles Factory2 en lui passant la *valeur* de t2 (qui donne sa
valeur à t dans le corps de Factory2).

Tu n'as fait que passer des valeurs de pointeurs (tu as "recopié" t2
dans t, d'une certaine façon).

Ce que tu voudrais, c'est que Factory2 affecte une valeur dans t2. Mais
pour cela il faut que Factory ait l'adresse de t2 (t2 est une variable
locale de main). Il y a deux solutions :

- la version "old school" pour les nostalgiques de C (dont moi) :

static void Factory2(Test * * t ) // un pointeur vers un pointeur
{
*t = new Test;
}
...
Test::Factory2(&t2); // on ne passe pas la valeur de t2,
// mais l'adresse de t2
// (en fait la valeur de l'adresse de t2)

- la version ultra-moderne :

static void Factory2(Test * & t) // une référence vers un pointeur
{
t = new Test;
}
...
Test::Factory2(t2); // comme Factory2 prend une référence, c'est
// bien l'adresse qui est passée, pas la valeur

Dans les deux cas, on passe à Factory2 une "adresse", qui lui permet de
modifier la variable dont on a passé l'adresse. C'est moins frappant
dans le second, plus visible dans le premier cas.

Oui, ça fait deux niveaux d'indirection (on passe l'adresse d'un
pointeur). Si tu trouves ça compliqué, remplace "Test *" (Test suivi
d'une étoile) par pointeur_t.

-- Alain.

P/S: si tu veux un conseil : ne passe pas à autre chose avant d'avoir
compris ça. C'est fondamental en C++. Et dans des tas d'autres langages,
même quand ils ne parlent pas de pointeurs.


Merci pour tes explications.
Il y a par contre quelquechose qui ne me parait pas très clair :
- si je déclare "void Func1(int a)", il va dupliquer le valeur du int de
l'appelant dans la variable "a" locale.
- si je reprends la même règles, pourquoi la fonction "void Func1(int*
a)" ne va pas copier la valeur du pointeur, qui est _l'adresse_ d'une
variable pointant vers un int de l'appelant ?
Alain Ketterlin
Le #24431431
TSalm
[...]
Il y a par contre quelquechose qui ne me parait pas très clair :
- si je déclare "void Func1(int a)", il va dupliquer le valeur du
int de l'appelant dans la variable "a" locale.



exactement

- si je reprends la même règles, pourquoi la fonction "void
Func1(int* a)" ne va pas copier la valeur du pointeur, qui est
_l'adresse_ d'une variable pointant vers un int de l'appelant ?



Non, ce n'est pas l'adresse d'une variable pointant vers un int, c'est
l'adresse d'un int.

L'adresse d'une variable pointant vers un int, ce serait int ** p.

Dans un appel à Func1 la valeur du pointeur est dupliquée. Tu peu x donc
modifier le int pointé. Mais pas le pointeur original. Si tu as :

int * ptr = ...
...
Func1(ptr);

après l'appel, tu es sûr que ptr a toujours la même valeur ( mais le int
pointé, s'il existe, peut avoir été modifié). Si tu à ©cris :

void Func2(int ** p) { ...}

et que tu as :

int * ptr = ...
...
Func2(&ptr); // <- note le &

alors Func2 peut modifier la valeur de p (puisqu'elle en a l'adresse --
ell peut écrire *p = <une autre adresse de int>), et aussi la valeur
pointée par p (puiqu'elle a l'adresse d'un pointeur de int -- il faut
alors écrire **p = 42).

-- Alain.
TSalm
Le #24435201

- si je reprends la même règles, pourquoi la fonction "void
Func1(int* a)" ne va pas copier la valeur du pointeur, qui est
_l'adresse_ d'une variable pointant vers un int de l'appelant ?



Non, ce n'est pas l'adresse d'une variable pointant vers un int, c'est
l'adresse d'un int.

L'adresse d'une variable pointant vers un int, ce serait int ** p.



Je comprends :
1- On commence par passer à la méthode un pointeur pointant vers NULL.
2- Il créé un pointeur et copie sa valeur pointée (qui est égale NULL)
3- Le "new" valorise ce pointeur avec une autre valeur
4- Par contre, le pointeur de l'appelant pointe toujours vers NULL
puisque ce n"est pas la même variable

Merci pour ces excellentes explications !
Publicité
Poster une réponse
Anonyme