Liste chainnée C++
Fermé
yalmazo1
Messages postés
1
Date d'inscription
mardi 29 janvier 2013
Statut
Membre
Dernière intervention
29 janvier 2013
-
Modifié par mamiemando le 1/02/2013 à 00:39
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 1 févr. 2013 à 01:03
mamiemando Messages postés 33446 Date d'inscription jeudi 12 mai 2005 Statut Modérateur Dernière intervention 20 décembre 2024 - 1 févr. 2013 à 01:03
A voir également:
- Liste chainnée C++
- Liste déroulante excel - Guide
- Liste déroulante en cascade - Guide
- Liste site streaming illégal - Accueil - Services en ligne
- Liste groupe whatsapp - Guide
- Liste de diffusion whatsapp - Guide
1 réponse
mamiemando
Messages postés
33446
Date d'inscription
jeudi 12 mai 2005
Statut
Modérateur
Dernière intervention
20 décembre 2024
7 812
Modifié par mamiemando le 1/02/2013 à 01:04
Modifié par mamiemando le 1/02/2013 à 01:04
Les lignes en gras correspondent à deux déclarations de constructeurs pour la classe Link.
- Le premier attend une const référence sur une instance de type Elem, et éventuellement un pointeur initialisé s'il est omis à NULL.
- Le second attend un pointeur optionnel qui est par défaut initialisé à NULL.
Vu que tu as fait du java tu sais ce qu'est une référence, puisqu'en java tous les passages de paramètres se font par référence. Le mot clé "const" signifie que la valeur référencée ne sera pas modifiée par la fonction.
En C++ tu as aussi les passages par recopie et les passages par pointeurs. En terme de syntaxe un passage par recopie et un passage par référence se comportent syntaxiquement de la même façon. Au niveau du comportement en lui même par contre, c'est plutôt le passage par référence et par pointeur qui se comportent de la même manière. La principale différence entre une référence et un pointeur, c'est qu'une référence doit toujours être initialisée et référencer une instance (tandis qu'un pointeur peut valoir NULL).
De manière générale écrire "toto *" signifie qu'on parle d'une adresse et qu'à cette adresse, on s'attend à trouver un objet de type toto. Quand on parle de "toto &", tout se passe comme si on manipulait une adresse et qu'on s'attendait à y trouver un objet de type toto. Enfin quand on parle de "toto", on recopie dans la pile un objet de taille toto, et donc la fonction travaille sur une recopie.
Ce petit exemple illustre la syntaxe et le comportement des trois types de passage de parametres
Lors de l'appel d'incrementer1, le x du main est recopié dans la pile. C'est cette recopie qui est altérée par incrementer1. Modifier x dans incrementer1 ne modifie donc pas la valeur de x dans le main, ce sont deux variables différentes.
Dans incrementer2, on fait un passage par référence. Donc on parle bien de la même variable, et modifier dans incrementer2 modifie la valeur de x dans main (puisque c'est une seule et même variable).
Dans incrementer3, on passe (par recopie) l'adresse de x (que j'ai notée px). Il s'agit de l'adresse mémoire de la variable x déclarée dans le main. Ainsi quand je regarde ce qui est à cette adresse *px, je manipule bien la variable x déclarée dans main.
Maintenant retournons sur ton code. Dans ton constructeur, tu peux initialiser directement ses membres en faisant appel au constructeur par copie (dans le cas général pour une classe "toto_t", le constructeur par copie est "toto(const toto_t & x)") qui est défini par défaut. Dans le code actuel tu fais appel à un opérateur "=" qui n'est pas forcément défini. De plus, vu que tout est public, autant utiliser directement une struct.
Ainsi le code ressemblerait plutôt à (en améliorant un peu les notations) :
Note que dans ton code ou celui-ci, on présuppose que la classe Elem dispose d'un constructeur par défaut (par exemple "toto_t()").
En terme de code, tu peux effectivement définir une classe "Link" qui correspond à un maillon de la liste (peu importe qu'elle soit simplement chaînée ou circulaire) et ensuite définir une classe list, une classe liste_circulaire etc... qui s'appuie dessus.
En tout cas dans la vraie vie, plutôt que de coder une liste chaînée on utiliserait directement la classe fournie par la STL (std::list).
https://forums.commentcamarche.net/forum/affich-37604421-introduction-a-la-stl-en-c-standard-template-library
Bonne chance
- Le premier attend une const référence sur une instance de type Elem, et éventuellement un pointeur initialisé s'il est omis à NULL.
- Le second attend un pointeur optionnel qui est par défaut initialisé à NULL.
Vu que tu as fait du java tu sais ce qu'est une référence, puisqu'en java tous les passages de paramètres se font par référence. Le mot clé "const" signifie que la valeur référencée ne sera pas modifiée par la fonction.
En C++ tu as aussi les passages par recopie et les passages par pointeurs. En terme de syntaxe un passage par recopie et un passage par référence se comportent syntaxiquement de la même façon. Au niveau du comportement en lui même par contre, c'est plutôt le passage par référence et par pointeur qui se comportent de la même manière. La principale différence entre une référence et un pointeur, c'est qu'une référence doit toujours être initialisée et référencer une instance (tandis qu'un pointeur peut valoir NULL).
De manière générale écrire "toto *" signifie qu'on parle d'une adresse et qu'à cette adresse, on s'attend à trouver un objet de type toto. Quand on parle de "toto &", tout se passe comme si on manipulait une adresse et qu'on s'attendait à y trouver un objet de type toto. Enfin quand on parle de "toto", on recopie dans la pile un objet de taille toto, et donc la fonction travaille sur une recopie.
Ce petit exemple illustre la syntaxe et le comportement des trois types de passage de parametres
#include <iostream> // par recopie void incrementer1(int x) { std::cout << "dans incrementer1:" << x << std::endl; // affiche 7 x++; std::cout << "dans incrementer1:" << << x << std::endl; // affiche 8 } // par référence void incrementer2(int & x) { x++; } // par pointeur void incrementer(int *px) { (*px)++; } int main() { int x = 7; incrementer1(x); std::cout << x << std::endl; // affiche 7 incrementer2(x); std::cout << x << std::endl; // affiche 8 incrementer3(&x); std::cout << x << std::endl; // affiche 9 return 0; }
Lors de l'appel d'incrementer1, le x du main est recopié dans la pile. C'est cette recopie qui est altérée par incrementer1. Modifier x dans incrementer1 ne modifie donc pas la valeur de x dans le main, ce sont deux variables différentes.
Dans incrementer2, on fait un passage par référence. Donc on parle bien de la même variable, et modifier dans incrementer2 modifie la valeur de x dans main (puisque c'est une seule et même variable).
Dans incrementer3, on passe (par recopie) l'adresse de x (que j'ai notée px). Il s'agit de l'adresse mémoire de la variable x déclarée dans le main. Ainsi quand je regarde ce qui est à cette adresse *px, je manipule bien la variable x déclarée dans main.
Maintenant retournons sur ton code. Dans ton constructeur, tu peux initialiser directement ses membres en faisant appel au constructeur par copie (dans le cas général pour une classe "toto_t", le constructeur par copie est "toto(const toto_t & x)") qui est défini par défaut. Dans le code actuel tu fais appel à un opérateur "=" qui n'est pas forcément défini. De plus, vu que tout est public, autant utiliser directement une struct.
Ainsi le code ressemblerait plutôt à (en améliorant un peu les notations) :
template <typename T> struct link_t { T element; link_t * next; link_t ( const T & element0, link_t * next0 = NULL ): element(element0), next(next0), {} link_t(link_t * next0 = NULL): element(), // cette ligne peut être sous-entendue next(next0), {} };
Note que dans ton code ou celui-ci, on présuppose que la classe Elem dispose d'un constructeur par défaut (par exemple "toto_t()").
En terme de code, tu peux effectivement définir une classe "Link" qui correspond à un maillon de la liste (peu importe qu'elle soit simplement chaînée ou circulaire) et ensuite définir une classe list, une classe liste_circulaire etc... qui s'appuie dessus.
En tout cas dans la vraie vie, plutôt que de coder une liste chaînée on utiliserait directement la classe fournie par la STL (std::list).
https://forums.commentcamarche.net/forum/affich-37604421-introduction-a-la-stl-en-c-standard-template-library
Bonne chance