Précédent   Forum du club des développeurs et IT Pro > Environnements de développement > WinDev > Contribuez
Contribuez Vos contributions pour la rubrique Windev : articles, cours, tutoriels, faq, comparatifs, tests, sources, ...
Partagez cette discussion sur d'autres réseaux sociaux : Viadeo Twitter Google Facebook Digg Delicious MySpace Yahoo
Réponse
 
Outils de la discussion
Publicité
'
Vieux 02/11/2010, 17h31   #1
bastiencb
Membre régulier
 
Inscription : août 2005
Messages : 56
Détails du profil
Informations forums :
Inscription : août 2005
Messages : 56
Points : 70
Points : 70
Par défaut Windev : Copie et prise de référence d'objets, opérateurs et règles d'affectation

Bonjour,

Voici une petite synthèse concernant les différents opérateurs d'affectation, en complément des informations de la documentation de PC-Soft accessible ici : http://doc.pcsoft.fr/fr-FR/?utilisation-des-objets.

Depuis la version 14 de Windev de nouveaux opérateurs d'affectation sont apparus (<- et <=).
Ces opérateurs permettent de copier ou de cloner des objets (instances de classe) entre eux.

Je part du principe arbitraire que :

-"Copier par valeur" un objet vers un autre consiste à dire que la valeur des membres de l'objet de destination sera identique à celle de l'objet source de la copie.
Dans ce cas, les deux objets sont indépendants l'un de l'autre.
Si vous modifiez la valeur d'un membre de l'objet A, cette valeur ne sera pas modifiée dans l'objet B.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Cla_Test
	iVal est un entier
	
objA est un Cla_Test
objB est un Cla_Test	

objA:iVal = 10
objB:iVal = 20

//Copie par valeur
objA <= objB
//La valeur de objA:iVal est 20

objA:iVal = 40
//La valeur de objA:iVal est désormais 40
//La valeur de objB:iVal est toujours 20
-"Copier par adresse" un objet vers un autre consiste à dire que l'adresse des membres de l'objet de destination sera identique à celle de l'objet source de la copie (Il s'agit d'une prise de référence).
Dans ce cas, les deux objets sont en fait un seul et même objet.
Si vous modifiez la valeur d'un membre de l'objet A, cette valeur sera aussi modifiée dans l'objet B.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
Cla_Test
	iVal est un entier
	
objA est un Cla_Test
objB est un Cla_Test	

objA:iVal = 10
objB:iVal = 20

//Copie par adresse
objA <- objB
//La valeur de objA:iVal est 20

objA:iVal = 40
//La valeur de objA:iVal est désormais 40
//La valeur de objB:iVal est désormais 40
L'utilisation des opérateurs =, <= ou <- pour "copier par valeur" ou "copier par adresse" des objets peut paraître simple de prime abord mais cela ce complique lorsque l'objet d'un côté ou de l'autre de l'opérateur d'affectation est de type "simple" ou de type dynamique, en particulier concernant l'opérateur =.

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//Objet dynamique :
ObjA est un Cla_Test dynamique
ObjA = allouer un Cla_Test

//Objet simple :
objB est un Cla_Test

objA:iVal = 10
objB:iVal = 20

objA = objB
objA:iVal = 40

//objB:iVal vaut désormais 40
//Si ObjA avait été un objet simple, objB:iVal vaudrait toujours 20
La copie par valeur ou par adresse d'un membre d'un objet dépend aussi du type de ce membre, en plus du type d'opérateur utilisé, comme démontré dans le tableau ci-dessous (cliquez une fois sur l'image puis une seconde fois pour l'agrandir) :



L'opération ObjA <= ObjB ou ObjA = ObjB peut ainsi aboutir à deux objets dont certains membres représentent en fait un seul et même membre partagé entre les deux instances et dont d'autres membres ont simplement une valeur identique.

De manière plus synthétique, on peut dire que :

Quelquesoit le type (dynamique ou non) des objets de part et d'autre de l'opérateur et le type de leurs membres, l'opérateur <- va :
-"Copier l'adresse" TOUT les membres de ces deux objets.

Quelquesoit le type (dynamique ou non) des objets de part et d'autre de l'opérateur, l'opérateur <= va :
-"Copier la valeur" de TOUT les membres de type primitif, objet simple, tableau local et tableau associatif de primitifs, de structures ou d'objets simples.
-"Copier l'adresse" de TOUT les membres de type objet dynamique, tableau, tableau dynamique et tableau associatif d'objets dynamiques (En gros des tableaux et tableaux de pointeurs).

Pour conclure, pour être certain de bien pouvoir copier par valeur ou par adresse (l'un ou l'autre) l'intégralité des membres d'un objet, le plus simple est de se servir de l'opérateur <= ou de l'opérateur <- (et non de l'opérateur =) et de toujours utiliser dans vos objets des membres de type objet simple, tableau local ou tableau associatif de primitifs, de structures ou d'objets simples (non dynamiques).

Notez qu'il est possible de charger un objet dynamique dans un membre de type objet simple sans qu'il n'y ai d'impact sur les règles d'affectation ci-dessus (A condition que cet objet soit lui même composé de membres non dynamiques ) :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
Cla_Test
	//Membres
	iVal est un entier
	oTruc est un Cla_Truc
	toTruc est un tableau local de Cla_Truc
	tAssooTruc est un tableau associatif de Cla_Truc

Cla_Truc
	//Membres
	iVal est un entier

oTest est un Cla_Test
oTruc est un Cla_Truc dynamique
oTruc = allouer un Cla_Truc

oTruc:iVal = 10	
oTest:oTruc <- oTruc
	
oTest2 est un Cla_Test
	
oTest2 <= oTest
oTest2:oTruc:iVal = 20

//oTest:oTruc:iVal vaut toujours 10

//L'utilisation d'un objet dynamique oTruc permet ce type de syntaxe
oTruc:iVal = 30

//oTest:oTruc:iVal vaut désormais 30
//oTest2:oTruc:iVal vaut toujours 20
Bonne prog
bastiencb est déconnecté   Envoyer un message privé Réponse avec citation 30
Vieux 03/11/2010, 08h53   #2
Hibernatus34
Membre émérite
 
Inscription : août 2010
Messages : 531
Détails du profil
Informations forums :
Inscription : août 2010
Messages : 531
Points : 998
Points : 998
Bonjour,

Habituellement, le mot "clonage" veut dire exactement le contraire de ce pour quoi vous l'employez, notamment en Java et C#, ce qui rend votre explication un peu difficile à lire. Je dirais plutôt "référencement".

En C++ le clonage est appelé copie (comme dans votre explication) car c'est le fonctionnement standard de "=", comme en WinDev avec un objet "non dynamique". Mais en Java/C# "=" copie une référence, et un objet doit être "Cloneable" pour reproduire le "=" de WinDev avec la méthode "clone()".
Hibernatus34 est déconnecté   Envoyer un message privé Réponse avec citation 20
Vieux 03/11/2010, 12h55   #3
Marco46
Expert Confirmé
 
Avatar de Marco46
 
Homme
Développeur informatique
Inscription : août 2005
Messages : 1 529
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 31
Localisation : France, Lot (Midi Pyrénées)

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : août 2005
Messages : 1 529
Points : 3 195
Points : 3 195
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//Objet dynamique :
ObjA est un Cla_Test dynamique
ObjA = allouer un Cla_Test

//Objet simple :
objB est un Cla_Test

objA:iVal = 10
objB:iVal = 20

objA = objB
objA:iVal = 40

//objB:iVal vaut désormais 40 !!!
//Si ObjA avait été un objet simple, objB:iVal vaudrait toujours 20 !!!
Évidemment que objB:iVal vaut 40 puisque ObjA est une référence (un pointeur si tu préfères). Donc forcément si tu lui dit de pointer au même endroit que B il vaut retourner la même valeur parce qu'il désigne la même valeur ...

D'une manière globale, je suis désolé, mais je trouve ton papier totalement imbouffable. Note que c'est pas de ta faute c'est juste le WLangage qui est imbouffable pour faire de la POO du coup c'est compliqué d'avoir quelque chose de clair.

Le meilleur moyen de ne pas se planter est d'utiliser systématiquement ce qu'ils appellent des objets "dynamiques" c'est à dire des références. Là on peut alors raisonner comme en Java ou C#. Et l'opérateur = est tout indiqué pour avoir plusieurs références sur la même instance.

EDIT : Et +1 avec Hibernatus, cloner c'est créer une instance à partir d'une autre identique à l'autre, c'est pas faire pointer deux références sur la même instance. C'est très très très une vraiment pas bonne idée de mélanger les termes comme ça. Pour un débutant ya rien de pire que ça. (Je me mets à la place du débutant en POO qui lit ça, il ne sait plus où il habite !)
__________________
"Toute personne croyant qu'une croissance exponentielle peut durer indéfiniment dans un monde fini est soit un fou, soit un économiste."
Kenneth E. Boulding

"/home/earth is 102% full ... please delete anyone you can."
Inconnu
Marco46 est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 03/11/2010, 14h18   #4
bastiencb
Membre régulier
 
Inscription : août 2005
Messages : 56
Détails du profil
Informations forums :
Inscription : août 2005
Messages : 56
Points : 70
Points : 70
Bonjour, et merci pour vos commentaires.

@Marco 36
Évidemment que objB:iVal vaut 40 puisque ObjA est une référence (un pointeur si tu préfères). Donc forcément si tu lui dit de pointer au même endroit que B il vaut retourner la même valeur parce qu'il désigne la même valeur ...

J'ai bien conscience qu'il s'agit d'une référence (un pointeur) et que le comportement est logique, je tente juste d'expliquer clairement pour les non initiés.

Le principal problème que je soulève ici est que l'utilisation de l'opérateur <= ou = peut aboutir a des objets dont les membres sont pour certains des pointeurs (références) et d'autres non selon leur type dans la déclaration de l'objet, ce qui n'est pas vraiment explicité dans l'aide de PC-soft.

Par exemple, le fait qu'un tableau associatif soit copié par valeur, alors qu'un tableau normal (non local) est copié par adresse avec l'opérateur <= ne va pas forcément de soi (y compris l'utilisation du mot clé "Local" pour les tableaux).

Dans tout les cas, ce qui me semble être le plus important est de toujours utiliser dans les objets des membres de type objet simple, tableau local ou tableau associatif de primitifs, de structures ou d'objets simples (non dynamiques) pour la simple raison qu'il sera possible par la suite de copier la valeur de tout les membres d'un objet vers un autre OU de copier leur références, au choix :

Si j'utilise un tableau dynamique t1 dans mon objet obj1, l'opération obj2 <= obj1 OU obj2 <- obj1 OU obj2 = obj1 fera TOUJOURS de mon membre t1 une référence partagée entre les instances.

Concernant l'utilisation des termes "Copier" ou "Cloner", je les ai remplacé respectivement par "Copie par valeur" et Copie par adresse" pour qu'il n'y ai pas de confusion avec les autres langages, ces notions de "Copie" ou "Clonage" n'existant pas dans Windev.

J'espère que ce sera plus clair pour tout le monde.
bastiencb est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 03/11/2010, 14h57   #5
Marco46
Expert Confirmé
 
Avatar de Marco46
 
Homme
Développeur informatique
Inscription : août 2005
Messages : 1 529
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 31
Localisation : France, Lot (Midi Pyrénées)

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : août 2005
Messages : 1 529
Points : 3 195
Points : 3 195
Citation:
Envoyé par bastiencb Voir le message
Bonjour, et merci pour vos commentaires.

@Marco 36
Évidemment que objB:iVal vaut 40 puisque ObjA est une référence (un pointeur si tu préfères). Donc forcément si tu lui dit de pointer au même endroit que B il vaut retourner la même valeur parce qu'il désigne la même valeur ...

J'ai bien conscience qu'il s'agit d'une référence (un pointeur) et que le comportement est logique, je tente juste d'expliquer clairement pour les non initiés.
Autant pour moi, c'était pas clair à la lecture.

Ceci dit, si le but est de faire découvrir la POO à des non-initiés je ne crois vraiment pas que le WLangage soit indiqué puisqu'il s'agit d'un langage procédural et non objet.
Si quelqu'un veut apprendre la POO il doit s'orienter vers des langages véritablement objets, Java, C# ou qui l'implémentent correctement C++, ...

Donc en fait, autant ton initiative part d'un bon sentiment et est utile (rien que pour le débat qu'elle provoque) mais par contre je la trouve mal ciblée. Elle devrait s'adresser à des gens qui connaissent déjà la POO et qui voudrait voir comment on peut faire avec Windev.

Citation:
Envoyé par bastiencb Voir le message
Le principal problème que je soulève ici est que l'utilisation de l'opérateur <= ou = peut aboutir a des objets dont les membres sont pour certains des pointeurs (références) et d'autres non selon leur type dans la déclaration de l'objet, ce qui n'est pas vraiment explicité dans l'aide de PC-soft.

Par exemple, le fait qu'un tableau associatif soit copié par valeur, alors qu'un tableau normal (non local) est copié par adresse avec l'opérateur <= ne va pas forcément de soi (y compris l'utilisation du mot clé "Local" pour les tableaux).

Dans tout les cas, ce qui me semble être le plus important est de toujours utiliser dans les objets des membres de type objet simple, tableau local ou tableau associatif de primitifs, de structures ou d'objets simples (non dynamiques) pour la simple raison qu'il sera possible par la suite de copier la valeur de tout les membres d'un objet vers un autre OU de copier leur références, au choix :

Si j'utilise un tableau dynamique t1 dans mon objet obj1, l'opération obj2 <= obj1 OU obj2 <- obj1 OU obj2 = obj1 fera TOUJOURS de mon membre t1 une référence partagée entre les instances.
Je suis pas du tout d'accord, utiliser systématiquement des objets dynamiques est de loin beaucoup plus clair. Tout fonctionne par adresse. Point. Si ensuite tu veux copier des objets ben tu te crées une méthode cloner() dans ta classe.

C'est plus clair car plus simple plutôt que d'aller s'embarrasser avec les termes PCSoft qui n'existent que dans le monde PCSoft.

Citation:
Envoyé par bastiencb Voir le message
Concernant l'utilisation des termes "Copier" ou "Cloner", je les ai remplacé respectivement par "Copie par valeur" et Copie par adresse" pour qu'il n'y ai pas de confusion avec les autres langages, ces notions de "Copie" ou "Clonage" n'existant pas dans Windev.
Oui c'est plus clair.
__________________
"Toute personne croyant qu'une croissance exponentielle peut durer indéfiniment dans un monde fini est soit un fou, soit un économiste."
Kenneth E. Boulding

"/home/earth is 102% full ... please delete anyone you can."
Inconnu
Marco46 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/11/2010, 16h11   #6
bastiencb
Membre régulier
 
Inscription : août 2005
Messages : 56
Détails du profil
Informations forums :
Inscription : août 2005
Messages : 56
Points : 70
Points : 70
Citation:
Ceci dit, si le but est de faire découvrir la POO à des non-initiés je ne crois vraiment pas que le WLangage soit indiqué puisqu'il s'agit d'un langage procédural et non objet.
Le but n'est pas de faire découvrir la POO mais d'en expliciter vite fait les concepts pour voir les équivalences en W-langage (Objet dynamique = Pointeur) et les subtilités -si je puis dire- (mot clé "Local" pour les tableaux etc...).

Citation:
Si quelqu'un veut apprendre la POO il doit s'orienter vers des langages véritablement objets, Java, C# ou qui l'implémentent correctement C++, ...
Personnellement, je trouve que Windev permet justement d'appréhender assez facilement les concepts de la POO, bien qu'il ne les implémente pas tous (Héritage multiple par exemple).
De plus l'ajout de fonctionnalités de reflection (à la java) et d'indirection sur les classes et les membres dans Windev 16 va apporter une grande souplesse et puissance dans la construction d'architectures complexes orientées objet dans Windev.

Citation:
Je suis pas du tout d'accord, utiliser systématiquement des objets dynamiques est de loin beaucoup plus clair. Tout fonctionne par adresse. Point. Si ensuite tu veux copier des objets ben tu te crées une méthode cloner() dans ta classe.
C'est justement le fait de devoir utiliser une méthode cloner() pour la copie par valeur de membres de type dynamique qui me pose problème.
A chaque fois que j'ajoute un membre, je dois modifier cette méthode...
Je veut pouvoir faire obj1 <= obj2 sans avoir à me soucier du type des membres de la classe, et ce quelque soit l'objet utilisé.
De cette manière, le code devient beaucoup plus générique.

De plus, je ne voit pas d’intérêt particulier à utiliser des membres dynamiques puisqu'il est possible de copier des références dans un membre non dynamique pour pouvoir profiter de la souplesse des pointeurs :

Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Cla_Test
	oTruc est un Cla_Truc

Cla_Truc
	iVal est un entier

oTest est un Cla_Test
oTruc est un Cla_Truc dynamique
oTruc = allouer un Cla_Truc

oTruc:iVal = 10
oTest:oTruc <- oTruc
	
oTest2 est un Cla_Test	
oTest2 <= oTest
oTest2:oTruc:iVal = 20

//oTest:oTruc:iVal vaut toujours 10

//L'utilisation d'un objet dynamique permet ce type de syntaxe
oTruc:iVal = 30

//oTest:oTruc:iVal vaut désormais 30
//oTest2:oTruc:iVal vaut toujours 20
bastiencb est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/11/2010, 16h47   #7
Marco46
Expert Confirmé
 
Avatar de Marco46
 
Homme
Développeur informatique
Inscription : août 2005
Messages : 1 529
Détails du profil
Informations personnelles :
Sexe : Homme
Âge : 31
Localisation : France, Lot (Midi Pyrénées)

Informations professionnelles :
Activité : Développeur informatique

Informations forums :
Inscription : août 2005
Messages : 1 529
Points : 3 195
Points : 3 195
Citation:
Envoyé par bastiencb
De plus, je ne voit pas d’intérêt particulier à utiliser des membres dynamiques puisqu'il est possible de copier des références dans un membre non dynamique pour pouvoir profiter de la souplesse des pointeurs :
J'ai toujours pas compris comment transposer une instance d'une classe non dynamique en Java ou C#.

En clair :
Code :
1
2
oObject est un CObject dynamique = allouer un COBject()
correspond en java à :
Code :
1
2
CObject object = new CObject();
Mais ça, ça correspond à quoi :
Code :
1
2
oObject est un CObject
Où est l'opérateur d'instanciation ?
Quel est l'intérêt d'une telle syntaxe à part créer de la confusion ?

Cette notion de dynamique/non dynamique est une pure invention de PCSoft ou alors j'ai loupé un truc.

La bonne et l'unique syntaxe devrait être quelque chose comme ça :
Code :
1
2
oObject est un CObject = allouer un COBject()
__________________
"Toute personne croyant qu'une croissance exponentielle peut durer indéfiniment dans un monde fini est soit un fou, soit un économiste."
Kenneth E. Boulding

"/home/earth is 102% full ... please delete anyone you can."
Inconnu
Marco46 est déconnecté   Envoyer un message privé Réponse avec citation 00
Vieux 03/11/2010, 17h27   #8
Jannus
Expert Confirmé Sénior
 
Inscription : décembre 2004
Messages : 19 652
Détails du profil
Informations forums :
Inscription : décembre 2004
Messages : 19 652
Points : 28 045
Points : 28 045
Merci de limiter cette discussion au code proposé.
Ceci n'est pas une discussion sur la POO
Jannus est déconnecté   Envoyer un message privé Réponse avec citation 10
Vieux 31/03/2011, 14h54   #9
JeromeDuc
Invité de passage
 
Inscription : octobre 2007
Messages : 4
Détails du profil
Informations forums :
Inscription : octobre 2007
Messages : 4
Points : 0
Points : 0
Bonjour,

article on ne peut plus interressant sur sujet (trop) peu documenté.

je rencontre néanmoins un petit soucis... je lis plus haut qu'il vaut mieux eviter les allocation de membres dynamiques mais que ce passe t'il quand on doit le faire quand meme ?

voici le code que j'ai posté sur le forum off aussi qui résume la situation :
Code :
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

Ma_Ligne 		un CLA_LIGNE_CDE
	nORDRE		est un entier
Ma_Commande 		est un CLA_CDE
	nID		est un entier
	tabLIGNE	est un tableau dynamique de 0 Ma_Ligne Dynamique


// creation d'une ligne a la commande dont l'ordre est 1
Ma_Commande:nID	= 1
Dimension(Ma_Commande:tabLIGNE,1)
Ma_Commande:tabLigne[1]:nORDRE = 1

// mon but est de creer une 2e commande, basé sur la premiere
Ma_Commande2		est un CLA_CDE <= Ma_Commande
Ma_Commande2:nID = 2
	// jusque ici tout va bien
	// Ma_Commande:nID  est egal à 1
	// et Ma_Commande2:nID est egale à 2

// et la, c'est le drame
Ma_Commande2:tabLigne[1]:nORDRE = 99
	// et la, on se rend compte qu'on a affaire a un pointeur
	// car :
	// Ma_Commande2:tabLigne[1]:nORDRE = 99
	// et 
	// Ma_Commande:tabLigne[1]:nORDRE = 99

// ok ok, c'est pas grave, on va tenter de contourner....
Ma_Commande:tabLigne[1]:nORDRE = 1
Ma_Ligne 		est un CLA_LIGNE_CDE <= Ma_Commande:tabLigne[1]
Ma_Ligne:nORDRE = 99
	// donc : 
	//Ma_Commande:tabLigne[1]:nORDRE = 1
	//Ma_Commande2:tabLigne[1]:nORDRE = 1 (normal, pointeur, CQFD)
	//Ma_Ligne:nORDRE = 99

// on tente de changer le pointeur vers le bon objet
Ma_Commande2:tabLigne[1] <- Ma_Ligne
	//RESULTAT
	//Ma_Commande:tabLigne[1]:nORDRE = 99 (?????)
	//Ma_Commande2:tabLigne[1]:nORDRE = 99
	//Ma_Ligne:nORDRE = 99
comme on peut le voir dans ma portion de code, une fois un pointeur recopié, il est impossible de changer son affectation sans impacté son origine.

j'espere que je me trompe !!!
JeromeDuc est déconnecté   Envoyer un message privé Réponse avec citation 01
Vieux 31/03/2011, 16h32   #10
Hibernatus34
Membre émérite
 
Inscription : août 2010
Messages : 531
Détails du profil
Informations forums :
Inscription : août 2010
Messages : 531
Points : 998
Points : 998
Code :
1
2
3
Ma_Commande 		est un CLA_CDE
	nID		est un entier
	tabLIGNE	est un tableau local de Ma_Ligne Dynamique
Le mot clé "dynamique" ne sert à rien sur un tableau.
Le mot clé "local" est important quand c'est un membre de structure/classe en revanche.
Hibernatus34 est déconnecté   Envoyer un message privé Réponse avec citation 00
Réponse
Outils de la discussion

Navigation rapide


Fuseau horaire GMT +2. Il est actuellement 03h12.


 
 
 
 
Partenaires

Hébergement Web