Passage par références en C++ - Programmation
Marsh Posté le 12-12-2000 à 17:11:53
Quand ont ne veut pas utliser les pointeurs.
En C++ quand ont veut affecter une valeur à un objet en le passant comme parametre à une fonction il faut donner un pointeur sur cette objet.ss
Avec le passage par reference on peut directerment donner l'objet.
class A
{
public :
ssint i ;
};
void foo1(A *a)
{
a->i = 0;
}
void foo2(A& a)
{
a.i = 0;
}
int main(void)
{
A aa;
foo1(&a);
foo2(a);
}
foo1 et foo2 font exactement la même chose;
Marsh Posté le 12-12-2000 à 17:12:59
Dans ton cas les références t'évites à passer les arguments par valeur qui nécessiterait une copie de l'objet en question. Et qui sait que les clases peuvent contenir beaucoup de membres et méthodes.
Un conseil: au lieu de passer tes objets par valeur passe les par référence constante si tu ne les modifies pas dans ta méthode. Ainsi tu as 'void f(const MyClass & myObject)' au lieu de 'void f(MyClass myObject)'.
Mais attention ça peut poser plein de problèmes de références constantes / non constantes si tu n'as pas bien défini tes classes.
Marsh Posté le 12-12-2000 à 17:15:53
seblamb > Arf, tu m'as devancé, mais nos posts sont complémentaires.
Marsh Posté le 12-12-2000 à 17:23:57
D'accord pour les arguments. Mais dans quels cas une fonction renvoie-t-elle une référence? Comme objet& f(...) par exemple.
Marsh Posté le 12-12-2000 à 19:32:12
Quand on apprend à programmer en C, on apprend vite que globalement, quand on veut modifier une donnée, il faut passer un pointeur dessus.
En C++, une référence, c'est un pointeur, ni plus ni moins. Sauf qu'on n'a jamais besoin de déréférencer le pointeur pour accéder à la donnée pointée (c'est-à-dire écrire *p ou p->..., un simple p ou p. ... suffit). C'est tout.
Après, l'utilité des pointeurs et des références, quand tu ne modifies pas tes données, c'est d'éviter des recopies inutiles de tes structures de données en appelant des fonctions. En passant un pointeur dessus, on recopie juste la valeur d'un pointeur sur ta structure de données, au lieu de recopier toute la structure de données. C'est moins coûteux. D'où l'utilité des const T* ou des const T&.
Enfin, certains prototypes d'opérateurs, genre operator=(), operator==() ou operator+(), sont standard, ils sont définis par le langage et tu ne dois pas les modifier. Donc si tu veux redéfinir l'opérateur d'affectation sur le type T, par exemple, tu devras écrire T& T:: operator(const T&), et pas un autre prototype, pas le choix.
Marsh Posté le 13-12-2000 à 11:07:38
Je rajouterai juste que les references sont aussi un moyen de securiser le code par rapport aux pointeurs.ss
Dans l'exemple de seblamb,ss
<table width="80%"><tbody><tr><td><font size="1" face="Arial, Verdana">Citation :</font><hr><font size="2" face="Arial, Verdana">void foo1(A *a)ss
{ss
a->i = 0;ss
}ss
void foo2(A& a)ss
{ss
a.i = 0;ss
}ss
</font><hr></td></tr></tbody></table>
Les deux fonctions font exactement la même chose. Cependant, pour celle dont le paramètre est un pointeur, rien ne t'assure que ce pointeur pointe bien sur un espace memoire alloué. Il peut être a null par exemple. Le compilateur ne criera jamais sur une erreur comme celle-la. Mais quand, à l'exécution, t'arrives à la ligness
a->i = 0;
Ben paf, ca plante. Avec les références, t'as pas ce type de bug.
Pour les fonctions renvoyant des réferences, je prends l'exemple de l'opérateur =. Le prototype type est celui la
NomClasse& operator=(const NomClasse&);
Dans cette fonction, le paramètre est une référence sur une autre instance de la classe que tu ne pourras pas modifier (const). Et pour cause, il est source de la copie, pas destination.ss
Pis la référence en retour (*this) sert quand tu veux faire plusieurs égalités en cascade par exemple.ss
Objet1 = Objet2 = Objet3;
Ici, on effectue Objet2 = Objet3, qui retourne une reference sur Objet2 (on va l'appeler RefObjet2).
Pis on effectue
Objet1 = RefObjet2.
De la même maniere, tu peux ecrire un truc du genre
Objet1::Fonction1(Objet2 = Objet3); par exemple.ss
On copie Obket3 dans Objet2 pis on passe la reference de Objet2 à la Fonction1.ss
Alors c'est pas tres propre, ca nuit a la lisibilite, mais ca passe.
J'ai repondu a ta question ?
Marsh Posté le 13-12-2000 à 11:45:16
DarthGuy merci!! J´y avais jamais pensé au coup de la sécurité sur l´espace mémoire alloué!! je sens que je vais plus jamais utiliser de pointeurs moi!!
Marsh Posté le 13-12-2000 à 12:21:32
Malheureusement il y a une grosse limitation :ss
on ne peut plus utlisiser de fonction virtuelles correctement !!!
class Ass
{
virtual void f1();
};
class B : public A
{
virutal void f1();
};
void ftest1{ A &a)
{
a.f1();
}
void ftest2{ A *a)
{
a->f1();
}
int main(void)
{
B b;
ftest1(b);
ftest2(&b);
}
dans cet example "ftest1(b)" va excuter la fonction "f1" de la calsse A et et pas celle de la classe B. Alors que dans "ftest2(&b)" ça fonctionne correctement
Marsh Posté le 13-12-2000 à 14:51:34
Aaaaargh!!! Tu as raison seblamb!!
Je veux plus entendre parler de références!! A part pour les copy constructors bien sûr..
Saloperie de C++!! Grrr vivement le Java..
Marsh Posté le 13-12-2000 à 14:57:46
Euh non, le polymorphisme marche bien avec les références !
Marsh Posté le 13-12-2000 à 15:28:28
Verdoux -> Tu as raison en fait c'était dans un cas beaucoup plux complexe que ça ne marchait pas.
Marsh Posté le 13-12-2000 à 16:25:51
Euhhh désolé Verdoux, mais alors mon VC++6 est VRAIMENT bizarre..
Parce que c une copie d´écran:
class m
{
public:
virtual void fct();
};
void m::fct()
{
int i=0;ss <= ici un breakpoint
}
class f: public m
{
public:
void fct();
};
void f::fct()
{
int i=1;
}
BOOL CTestReferencesApp::InitInstance()
{
f fille;
((m)fille).fct();
return FALSE;
}
Et je me tape le breakpoint!!!ss
Avec ((m*)&fille)->fct() non... Help!!
Marsh Posté le 13-12-2000 à 16:34:09
Oui, mais là c'est normal !
Avec (m)fille tu crées un objet temporaire de type m sur lequel t'appelles la fonction fct.
Marsh Posté le 13-12-2000 à 16:41:34
Bien vu Verdoux!! Ouf mon compiler est pas si con!!
Effectivement j´aurais du écrire ((m&)fille).fct(); et non pas ((m)fille).fct();..
C cool j´apprends bcp ds ce formum!!
Marsh Posté le 13-12-2000 à 18:07:15
Quand je dis que C++ n'est vraiment pas adapté à ceux qui apprennent à programmer... Vous réalisez le nombre de choses qu'il faut garder à l'esprit pour ne pas faire d'erreur de programmation ?
Marsh Posté le 15-12-2000 à 11:14:05
Et ben non, DarthGuy, l´emploi de références ne permet pas du tout de securiser le code par rapport aux pointeurs!! je reprends ton exemple:
void foo2(A& a)ss
{ss
a.i = 0;ss
}
Et je fais:
void Main()
{
foo2(*(A*)0);
}
Et c pareil qu´avec des pointeurs, je peux passer une référence sur un object non instancié!!
Marsh Posté le 15-12-2000 à 14:11:16
Bien joué H4dd3R !!!
C'est clair, j'avais pas pensé à ça... C'est un peu tordu mais c'est clair qu'on peut le planter comme ça.
Tant pis, je retenterai ma chance la prochaine fois !
PS : Je confirme BifaceMcLeOD. T'as tout à fait raison. La preuve !
Marsh Posté le 14-01-2001 à 00:33:36
Je suis bien, d'accord avec vous tous mais vous oubliez un truc : les pointeurs, c bien quand c plus pratique qu'un passage par référence. Et encore faut pas oublier de libérer la mémoire
Marsh Posté le 12-12-2000 à 16:57:43
J'ai du mal à comprendre à quoi ça sert de renvoyer des valeurs par référence dans les fonctions d'une classe. Par exemple pour surdéfinir l'opérateur d'affectation.
Et quand doit-on passer les arguments par référence?