ajout dynamique de variables dans un objet

ajout dynamique de variables dans un objet - C++ - Programmation

Marsh Posté le 20-07-2006 à 00:20:48    

bonjour à tous,
 
je voulais savoir si il est possible de rajouter de manière dynamique une/des variable/s  (de différents types) à une instance de classe.  
Je l'ai déjà fait en python mais je n'arrive pas à savoir si on peut le faire en C++.
 
exemple (pseudo code):
 
class test{
   public:
       test();
       ....
};
...
 
test t;
int val(3);
 
t.addAttribute(val);
 
cout << "val "<< t.getAttribute(val);
 
 

Reply

Marsh Posté le 20-07-2006 à 00:20:48   

Reply

Marsh Posté le 20-07-2006 à 10:43:51    

utilise std::vector<int>

Reply

Marsh Posté le 20-07-2006 à 10:50:52    

En quoi cela répond à ce que je veux faire ? je ne vois pas pourquoi utiliser un vecteur de int dans le cas ou je souhaiterai ajouter des vairables de types différents.  
Pourrais tu expliquer ?


Message édité par lokida le 20-07-2006 à 10:53:49
Reply

Marsh Posté le 20-07-2006 à 11:25:39    

tu ne peux pas trivialement avoir des collections de types différents.

Reply

Marsh Posté le 20-07-2006 à 13:26:40    

typelist, tuple, map static je vois que ça ...
C'est du lourd et je vois pas bien l'intéret de la chose o_O

Reply

Marsh Posté le 22-07-2006 à 11:48:56    

Google : design pattern decorator.

Reply

Marsh Posté le 22-07-2006 à 12:46:30    

est-ce vraiment ce qu'il cherche à faire ? C'est plus orienté comportement que valuer ou m'égare-je ?
 
J'ai du mal à voir deja lebut initial de lokida
 

Reply

Marsh Posté le 22-07-2006 à 13:46:07    

tu ne peux pas ajouter à une liste des variables de types differents sans que la liste aie "moyen" de savoir au moins la taille de ton type :)
Deux solutions :
 
Si tu veux ajouter des valeurs typiques comme chaines de caractères, nombres à virgules ou entiers... crée une classe qui gère tout ca...
j'en ai codé une pour mon moteur 3D qui est assez bien foutue à mon gout ^^ lol jpeux te la filer si tu veux.
Ensuite, tu fais un pti std::vector<value>   ou value est ta classe qui peut contenir le type que tu veux.
 
Sinon, tu peux faire un membre   addatribute( (void*) donnees , size_t taille )
ensuite, dans le corps suffira de metre une pair qui contient données et taille. A l'appel de addatribute, tu fais un memcpy vers un nvo pointeur void ou t'as alloué la taille kil falait. (je sais pas si je suis clair...)
Bon, c'est pas SUPER pratique pour s'en servir, mais au moins tu peux spécifier nimporte quel type ;)
 
 
ps : je te recommande la premiere solution
 
 
[edit] sinon faut attendre les types managés du c++ ...aparement yaurra une gestion "intelligente" des types de données... suffira de définir la variable avec le keyword "auto" ....... enfin ca reste à voir  :heink:   à suivre...

Message cité 1 fois
Message édité par icareo le 22-07-2006 à 13:48:29

---------------
tutos de programmation 3D :
Reply

Marsh Posté le 22-07-2006 à 15:12:12    

euh t'es sur d'être qualifié pour donner des conseils ? là à part des boniments de C, je ne vois rien de valable.

Reply

Marsh Posté le 22-07-2006 à 19:52:53    

boost::tuple quoi, voire loki::typelist pour une version compile time.
Sinon effectivement, un Decorator ^^

Reply

Marsh Posté le 22-07-2006 à 19:52:53   

Reply

Marsh Posté le 22-07-2006 à 21:24:22    

lokida a écrit :

je voulais savoir si il est possible de rajouter de manière dynamique une/des variable/s  (de différents types) à une instance de classe.  
Je l'ai déjà fait en python mais je n'arrive pas à savoir si on peut le faire en C++.


 
 
Comme je comprends ta question, tu veux dynamiquement ajouter une donnée membre à la classe, qui n'est valable que pour une instance donnée ? ie que sizeof( instance_de_test ) ne soit pas constant ?
Ce n'est pas faisable en C++. Les mécanismes de réflexion ne sont pas dans le langage, il faudra faire sans.
 
(vu que je connais pas les possibilitées de Python, je ne suis pas sur que ma réponse corresponde bien à ta question)


Message édité par ++fab le 22-07-2006 à 22:57:57
Reply

Marsh Posté le 22-07-2006 à 22:11:12    

que ce soit en python ou en autre chose, je ne vois pas ce qu'on peut faire d'une liste d'objets si ce n'est s'ils respectent un même protocole. Alors un pauvre vector<A*> suffira.

Reply

Marsh Posté le 22-07-2006 à 22:28:24    

icareo a écrit :

tu ne peux pas ajouter à une liste des variables de types differents sans que la liste aie "moyen" de savoir au moins la taille de ton type :)


 
dans un container<T>, on peut y ranger des objets de type T ou implicitement convertible en T.
Pour utiliser -- je simplifie -- un container<T>, T doit être un type complet (on peut donc connaitre sa taille).
 

Citation :

Deux solutions :
[ ... ] tu fais un pti std::vector<value>   ou value est ta classe qui peut contenir le type que tu veux.


et value est un paramètre template de la classe test. On peut donc ranger des objets de type "value".
 

Citation :

Sinon, tu peux faire un membre   addatribute( (void*) donnees , size_t taille )
ensuite, dans le corps suffira de metre une pair qui contient données et taille. A l'appel de addatribute, tu fais un memcpy vers un nvo pointeur void ou t'as alloué la taille kil falait. (je sais pas si je suis clair...)


(merci d'écrire en français) Et comment invoques-tu new ?
 
 

Citation :

sinon faut attendre les types managés du c++ ...aparement yaurra une gestion "intelligente" des types de données... suffira de définir la variable avec le keyword "auto" ....... enfin ca reste à voir  :heink:   à suivre...


types managées ? auto servira à faire de l'inférence de type. Ce n'est pas à priori ce que l'on souhaite faire ici.  
 

Reply

Marsh Posté le 22-07-2006 à 22:51:25    

Taz a écrit :

que ce soit en python ou en autre chose, je ne vois pas ce qu'on peut faire d'une liste d'objets si ce n'est s'ils respectent un même protocole. Alors un pauvre vector<A*> suffira.


Avec A classe de base ? C'est une contrainte forte (mais dans les moeurs) que de demander à ce que tout les objets que l'on veut stocker soit hérités de A. Pourquoi ne pas utiliser un std::vector< boost::variant<int,double,Foo> > ? Je commence à utiliser ceci régulièrement, j'en suis content, et je ne suis pas au bout de mes surprises ...

Reply

Marsh Posté le 22-07-2006 à 23:59:47    

bof, le variant je préfèrerais any.
 
Je dis pas non, mais pour faire des tonnes de python, je ne me suis jamais retrouvé dans un cas d'une liste hétérogène (objets ne répondant pas au même protocole), donc je ne vois pas de cas.
 
Je ne vois pas de contrainte à avoir une classe de base, je pense que c'est bien plus facile un pauvre appel de méthode que des switch à n'en plus finir.

Reply

Marsh Posté le 23-07-2006 à 10:16:35    

Taz a écrit :

bof, le variant je préfèrerais any.


L'usage est assez proche. Le variant est plus puissant, à condition que tu puisses connaitre la liste de types que tu veux pouvoir gérer, que tu puisses payer pour un temps de compilation plutot long, et que tu acceptes des messages d'erreurs imbitables -- si t'as pas un outil pour parser les messages d'erreurs, c'est foutu.
 

Citation :

Je dis pas non, mais pour faire des tonnes de python, je ne me suis jamais retrouvé dans un cas d'une liste hétérogène (objets ne répondant pas au même protocole), donc je ne vois pas de cas.


 
J'ignorais que l'on puisse écrire des listes hétérogènes en python (et je ne sais pas ce que signifie protocole dans ce contexte), mais en C++, on ne peut écrire que des liste (+ ou -) de même type, lui même suffisament malin pour donner l'impression qu'il est hétérogène (je pense au variant).
Après, si ces types doivent avoir des propriétées communes, la façon de le garantir pour un variant est une bonne question -- même avec les concepts, je ne vois pas. Pour le cas d'une hiérarchie avec classe de base abstraite, c'est trivial.
 
 
 

Citation :

Je ne vois pas de contrainte à avoir une classe de base,


Les types fondamentaux & compounds n'en ont pas; une classe sur laquelle tu n'as pas la main n'a pas de classe de base; une classe a l'interface d'un singleton, et on accède à l'instace via Foo::instance(), etc.
 

Citation :

je pense que c'est bien plus facile un pauvre appel de méthode que des switch à n'en plus finir.


la virtualité de la fonction impose une contrainte supplémentaire, même si elle est souvent acceptée. Note que la solution utilisant une classe de base impose une gestion dynamqiue de la mémoire.
Il n'y a pas de switch à écrire lorsqu'on utilise un variant, puisqu'on peut y accéder à compile-time via apply_visitor.
 

Reply

Marsh Posté le 23-07-2006 à 12:09:17    

++fab a écrit :

L'usage est assez proche. Le variant est plus puissant, à condition que tu puisses connaitre la liste de types que tu veux pouvoir gérer, que tu puisses payer pour un temps de compilation plutot long, et que tu acceptes des messages d'erreurs imbitables -- si t'as pas un outil pour parser les messages d'erreurs, c'est foutu.

bah si tu connais la liste des types que tu vas y mettre, alors tu sais ce que tu vas en faire, alors ça risque de passer tout seul avec de l'héritage. je trouve le variant assez batard et je ne pense pas que ça corresponde du tout ici de même que qu'une collection d'union n'aurait pas apporter grand chose.
 

Reply

Marsh Posté le 23-07-2006 à 13:26:22    

Taz a écrit :

bah si tu connais la liste des types que tu vas y mettre, alors tu sais ce que tu vas en faire,


Au départ, je sais ce que je vais faire, et ça implique assez souvent que l'on connaisse les types auxquels on va avoir affaire.
 

Citation :

alors ça risque de passer tout seul avec de l'héritage.


Peut-être, mais mon avis est que c'est une contrainte forte.
 

Citation :

je trouve le variant assez batard

 
?
 

Citation :

et je ne pense pas que ça corresponde du tout ici de même que qu'une collection d'union n'aurait pas apporter grand chose.


J'utiliserai soit un std::vector< boost::variant< ... > >, soit un std::vector< boost::any >, soit un std::vector<T> (std::vector<> ou autre container standard).  Au PO de voir quel est son besoin ...
(on peut voir un variant comme une union acceptant les types pas forcément aggregate, et la visitation à la compilation.)


Message édité par ++fab le 14-08-2006 à 20:10:08
Reply

Marsh Posté le 23-07-2006 à 13:51:18    

désolé si j'ai écrit un peu de travers... j'étais pas très net qd j'ai écrit mon précédent message...
 
++ fab: Et comment invoques-tu new ?
je suppose que je pensais à un malloc tout con.
Ceci dit, tout le monde n'a pas forcément envie d'utiliser des librairies comme boost... pour un problème qui n'en a pas forcément besoin :)
 
taz : merci du compliment, mais sans pour autant me la ramener, je pense que je commence à bidouiller correctement le c++ :-/
Seulement je code generalement pour un moteur 3D... donc j'aurrais tjrs tendance à donner des conseils utilisant au maximum le c++ natif, sans recours à des librairies aux performances prouvées, mais incertaines face à une implémentation maison.
 
 
ps: vous partez en débat la... je sais pas si lokida a vrmt eu sa réponse...


---------------
tutos de programmation 3D :
Reply

Marsh Posté le 23-07-2006 à 14:33:54    

icareo a écrit :

++ fab: Et comment invoques-tu new ?
je suppose que je pensais à un malloc tout con.


s/new/malloc, et réponds à la question.
 

Citation :

Ceci dit, tout le monde n'a pas forcément envie d'utiliser des librairies comme boost... pour un problème qui n'en a pas forcément besoin :)


Si tu as une alternative standard et non casse gueule, je suis tout ouie -- et j'ai lu ton post précédent.
 

Citation :

ps: vous partez en débat la...


ça te dérange ?


Message édité par ++fab le 23-07-2006 à 14:34:13
Reply

Marsh Posté le 23-07-2006 à 14:57:27    

Que d'agressivité...
Bref, en fait je suis pas sur que tu aies pigé ce que je veux dire... vu qu'en fait ta question n'a pas bcp de sens à mon gout ... ou alors j'ai pas pigé ce que tu demandais. Mon idée était vraiment toute conne, et peu pratique pour s'en servir :
 
class test
{
public:
  test();
  ~test();
  void addAttribute( void * ptr,  size_t   sz )
 {
     void* mem = malloc(sz);
     memcpy(mem, ptr, sz );
     attributes.push_back( mem );
  }
  getAttribute( .....); // bon, la faut voir sur quoi on se base pr récup un atribut... et modifier tout en fonction
private:
  std::vector<void*> attributes;
};
 
 
 
int main()
{
   int entier = 12;
   double reel = 1.2454d;
   maclasse c = new maclasse[5];
   test t;
   t.addAttribute( &entier, sizeof( int ) );
   t.addAttribute( &reel , sizeof( double) );
   t.addAttribute( &c ,  sizeof( maclasse) * 5 );
}
 
 
 
 ou est le pb ? :s
 
 
[edit] mais comme je l'ai dit : c'est chiant à utiliser a cause di sizeof ;)

Message cité 2 fois
Message édité par icareo le 23-07-2006 à 15:09:28

---------------
tutos de programmation 3D :
Reply

Marsh Posté le 23-07-2006 à 15:00:03    

Et ceci dit, non, le débat ne me dérange pas, c'était une précision ... car un débat c'est bien, mais à la base, yavait une question posée...
 
 

Citation :

Si tu as une alternative standard et non casse gueule, je suis tout ouie


Je n'ai pas d'alternative "standard" pour remplacer boost dans son intégralité, mais j'estime que si c'est juste pour stocker quelques classes de types differents, integrer boost dans le projet est, certes pas très lourd à faire, mais ... superflu  :heink:   A plus forte raison si on a besoin d'une très bonne optimisation. Je suis contre l'utilisation des libs à tout va, pour tout sujet à n'importe quelle occasion... Il y a des fois ou elles peuvent être aisément remplacées par un bout de code plus rapide (car bien spécifique à ce qu'on veut faire), et pas forcément moins fiable !
 
(précision : le code ci dessus est certes plus rapide, mais pas aussi fiable, je l'avoue... mais c'est une solution que j'utiliserais pas.  :lol: )
 
[re edit] je veux pas non plus tomber sur un débat sur l'utilité des libs face à un code maison... il est évident que les libs standard sont très pratiques, très bien foutues, et très portables / généralistes / etc.... personne n'en doute... mais il ne faut abuser de rien  ;)

Message cité 1 fois
Message édité par icareo le 23-07-2006 à 15:19:46

---------------
tutos de programmation 3D :
Reply

Marsh Posté le 23-07-2006 à 16:07:30    

icareo a écrit :

Que d'agressivité...
[...]
getAttribute( .....); // bon, la faut voir sur quoi on se base pr récup un atribut... et modifier tout en fonction.
[...]
ou est le pb ? :s


Dans les bidouilles qui vont être nécessaire pour implémenter getAttribute. Lors de la conversion en void*, le type est définitivement perdu.

Reply

Marsh Posté le 23-07-2006 à 16:09:39    

d'ou l'interet de "modifier en fonction", une map, ou un pair est bienvenu ;)


---------------
tutos de programmation 3D :
Reply

Marsh Posté le 23-07-2006 à 16:30:37    

icareo a écrit :

Et ceci dit, non, le débat ne me dérange pas, c'était une précision ... car un débat c'est bien, mais à la base, yavait une question posée...


Relis la question, relis le débat. Et si tu veux dire à quelqu'un de se taire, demandes toi bien si tu en as l'autorité suffisante.
 

Citation :

Je n'ai pas d'alternative "standard" pour remplacer boost dans son intégralité, mais j'estime que si c'est juste pour stocker quelques classes de types differents, integrer boost dans le projet est, certes pas très lourd à faire, mais ... superflu  :heink:   A plus forte raison si on a besoin d'une très bonne optimisation. Je suis contre l'utilisation des libs à tout va, pour tout sujet à n'importe quelle occasion... Il y a des fois ou elles peuvent être aisément remplacées par un bout de code plus rapide (car bien spécifique à ce qu'on veut faire), et pas forcément moins fiable !


Ce n'est pas une obligation d'intégrer boost (ou d'autres libs). Il faut juste savoir si on est capable d'écrire du code robuste, et de le maintenir. Quand à l'optimiser, n'en parlons pas.


Message édité par ++fab le 23-07-2006 à 16:31:45
Reply

Marsh Posté le 23-07-2006 à 16:33:34    

icareo a écrit :

d'ou l'interet de "modifier en fonction", une map, ou un pair est bienvenu ;)


Je pense que si tu pousse le "mettage des mains dans le cambouis" à fond, tu te rendras compte qu'une lib qui te fait le boulot n'est pas de trop.

Reply

Marsh Posté le 23-07-2006 à 16:51:57    

Citation :


Relis la question, relis le débat. Et si tu veux dire à quelqu'un de se taire, demandes toi bien si tu en as l'autorité suffisante.  


Faut arreter avec ca, c'était une remarque ! Une question a été posée, faut pas l'oublier trop non plus... c'est tout ce que j'ai essayé de dire, c'est pas vraiment comme si j'avais dit "ta gueule", auquel cas je comprends que ca aurrait pu etre mal pris !
Je ne veux pas faire de lecons, mais depuis quand ya des rapports d'autorité autre que celle d'un modulateur, dans les forums ?
Ca fait (que) 7 ans que je fais du C++, je sais bien que ca ne fais pas de moi un codeur de folie, mais je sais coder quand meme... donc j'essaye d'aider, je n'ai jamais prétendu faire la loi!  :)
 
Quand au petit commentaire sur le code, je te rapelle qu'il a été fait à la volée, sans se poser la moindre question ... histoire d'expliquer la solution que j'avais bien précisée comme étant foireuse plus haut.
 
Ceci dit, suivant l'applications qu'on en fait, ca peut remplir les conditions mieux que des libs "toutes faites". Mais comme je l'ai dit plus haut, le débat  entre  "libs toutes faites" et "mains dans le cambouis" ne m'interesse pas ! Je n'en ai que trop lu à ce sujet.
 
Bref. Je ne crois pas qu'il y ait grand chose de constructif à rajouter.


---------------
tutos de programmation 3D :
Reply

Marsh Posté le 23-07-2006 à 18:44:58    

icareo a écrit :

Citation :


Relis la question, relis le débat. Et si tu veux dire à quelqu'un de se taire, demandes toi bien si tu en as l'autorité suffisante.  


Faut arreter avec ca, c'était une remarque ! Une question a été posée, faut pas l'oublier trop non plus...


Et tu as décrété que je n'essayais pas de répondre à la question posée ? goto la remarque à laquelle tu réponds.
 

Citation :

Je ne veux pas faire de lecons, mais depuis quand ya des rapports d'autorité autre que celle d'un modulateur, dans les forums ?

? Je te retournes la question.
 

Citation :

Ceci dit, suivant l'applications qu'on en fait, ca peut remplir les conditions mieux que des libs "toutes faites". Mais comme je l'ai dit plus haut, le débat  entre  "libs toutes faites" et "mains dans le cambouis" ne m'interesse pas ! Je n'en ai que trop lu à ce sujet.


ça ne t'intéresse pas, alors je n'ai pas le droit d'en parler ?
 

Citation :


Bref. Je ne crois pas qu'il y ait grand chose de constructif à rajouter.


Très élégant, ta façon d'avoir le dernier mot.  

Reply

Marsh Posté le 23-07-2006 à 22:03:31    

++fab a écrit :

Avec A classe de base ? C'est une contrainte forte (mais dans les moeurs) que de demander à ce que tout les objets que l'on veut stocker soit hérités de A. Pourquoi ne pas utiliser un std::vector< boost::variant<int,double,Foo> > ? Je commence à utiliser ceci régulièrement, j'en suis content, et je ne suis pas au bout de mes surprises ...


Sérieusement, à ce niveau-là, je pense qu'il faut commencer à songer à changer langage. :/
Ocaml et Haskell gèrent ce genre de choses de façon infiniment plus élégante.
 
Mais de façon générale, je suis d'accord avec Taz. Les collections hétérogènes, à part p-ê dans l'écriture d'un compilo pour un langage tordu, c'est quand même assez louche, il faut p-ê se poser la question si l'architecture n'est pas de traviole.

Message cité 1 fois
Message édité par el muchacho le 23-07-2006 à 22:09:32

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 23-07-2006 à 22:55:26    

el muchacho a écrit :

Sérieusement, à ce niveau-là, je pense qu'il faut commencer à songer à changer langage. :/
Ocaml et Haskell gèrent ce genre de choses de façon infiniment plus élégante.


Si tu peux exposer brièvement la version haskell, je suis preneur :)
 

Citation :

Mais de façon générale, je suis d'accord avec Taz. Les collections hétérogènes, à part p-ê dans l'écriture d'un compilo pour un langage tordu, c'est quand même assez louche, il faut p-ê se poser la question si l'architecture n'est pas de traviole.


Ce sont bien des collections homogènes, d'un type un peu spécial.
Au contraire, je réfléchirai à deux fois avant d'imposer un hack à base de classe de base à tout le monde.  

Reply

Marsh Posté le 24-07-2006 à 01:11:01    

icareo a écrit :

Que d'agressivité...
Bref, en fait je suis pas sur que tu aies pigé ce que je veux dire... vu qu'en fait ta question n'a pas bcp de sens à mon gout ... ou alors j'ai pas pigé ce que tu demandais. Mon idée était vraiment toute conne, et peu pratique pour s'en servir :
 
class test
{
public:
  test();
  ~test();
  void addAttribute( void * ptr,  size_t   sz )
 {
     void* mem = malloc(sz);
     memcpy(mem, ptr, sz );
     attributes.push_back( mem );
  }
  getAttribute( .....); // bon, la faut voir sur quoi on se base pr récup un atribut... et modifier tout en fonction
private:
  std::vector<void*> attributes;
};
 
 
 
int main()
{
   int entier = 12;
   double reel = 1.2454d;
   maclasse c = new maclasse[5];
   test t;
   t.addAttribute( &entier, sizeof( int ) );
   t.addAttribute( &reel , sizeof( double) );
   t.addAttribute( &c ,  sizeof( maclasse) * 5 );
}
 

vous n'avez un POD, allez en prison, ne touchez pas 20000F

Reply

Marsh Posté le 24-07-2006 à 07:57:33    

++fab a écrit :

Note que la solution utilisant une classe de base impose une gestion dynamqiue de la mémoire.


 
Pourrais-tu detailler stp ? Je ne suis pas sur d'avoir compris.
 
 
 
Pour repondre a Icareo qui demande ou est le probleme dans son code : si tu essaie ce code avec des classes dans ton conteneur, tu verras que le constructeur ne sera jamais appele. Le destructeur non plus d'ailleurs. (C'est exactement ce que sous entend Taz, mais je pense que ma version est plus parlante!). Il faut necessairement utiliser new.
 
Et accessoirement, je ne vois pas du tout comment tu comptes implementer getAttribute sans le rendre dependant d'a peu pres toutes les classes de ton programme. Y'en a vraiment besoin de ce truc ?  :D  
 

Reply

Marsh Posté le 24-07-2006 à 18:21:47    

C'est toujours pareil :/ tout dépend ce que tu veux en faire... si tu comptes stocker 100 types differents, c'est illusoire. Je le re-répète, ce n'est pas une solution que j'utiliserais !
Sans vouloir défendre mon pseudo code, si c'est par exemple pour stocker en une et meme classe un nombre connu de classes, dans un ordre connu (pour une communications entre threads par exemple...) ce genre de solutions rapidement codée peut se montrer efficace, vu qu'à la lecture  des classes stockée, on sait quelles sont les classes et dans quelles ordres elles sont ! getAttribute renverra alors un (void*). inutile d'aller plus loin, c'est sur que tout dépend des besoins qu'on, mais on va faire comme si je conaissais le proverbe: Des fois, faut pas chercher un marteau qd le pouce suffit à enfoncer le clou. (uh?!)
 
Quand au constructeur, faut l'appeler avant de stocker la classe bien sur... et ya aucun problème ?!
ps: 2 ptis problèmes de syntaxe dans mon code... mais bon ^^
 
En tous cas, ca fait plaisir de voir la chaleur, l'humilité et le répondant des membres de ce forum qui savent un peu coder... :(


---------------
tutos de programmation 3D :
Reply

Marsh Posté le 24-07-2006 à 20:06:14    

Ace17 a écrit :

Pourrais-tu detailler stp ? Je ne suis pas sur d'avoir compris.


Quand tu utilises le polymorphisme dynamique, tu as souvent besoin de manipuler des pointeurs. Pour s'assurer de la validité d'un pointeur, on fait souvent des allocations dynamiques supplémentaires (via clone() par exemple ).
 

Citation :

Pour repondre a Icareo qui demande ou est le probleme dans son code : si tu essaie ce code avec des classes dans ton conteneur, tu verras que le constructeur ne sera jamais appele. Le destructeur non plus d'ailleurs. (C'est exactement ce que sous entend Taz, mais je pense que ma version est plus parlante!). Il faut necessairement utiliser new.


Je ne comprends pas. Le constructeur est bien appelé. Pour le destructeur -- à condition qu'on arrive à reformer l'objet -- il sera bien appelé à la fin de la durée de vie de l'objet.
Ce que sous-entends Taz, ce sont les propriétées des POD. On peut leurs appliquer sainement un memcpy ou un memmove (§3.9.2, §3.9.3 ).
Le memcpy ne va donc marcher que pour les POD. En fait, je ne vois aucune manière d'implémenter correctement cette solution.

Reply

Marsh Posté le 24-07-2006 à 20:12:04    

icareo a écrit :

Sans vouloir défendre mon pseudo code, si c'est par exemple pour stocker en une et meme classe un nombre connu de classes, dans un ordre connu (pour une communications entre threads par exemple...) ce genre de solutions rapidement codée peut se montrer efficace, vu qu'à la lecture  des classes stockée, on sait quelles sont les classes et dans quelles ordres elles sont ! getAttribute renverra alors un (void*).


(voir la remarque de Taz sur les POD et ma réponse)
Et après, que fais-tu tu void* ? un cast ? un memcpy ? Je ne vois aucune manière de faire.

Reply

Marsh Posté le 24-07-2006 à 20:20:50    

++fab a écrit :


Et après, que fais-tu tu void* ? un cast ? un memcpy ? Je ne vois aucune manière de faire.


 
Si c'etait juste ca le probleme, on peut construire une copie en castant l'adresse et en la déférencant ?
 

Code :
  1. objet a;
  2. const void * p = &a;
  3. objet b(* reinterpret_cast<const objet *>(p));

Reply

Marsh Posté le 24-07-2006 à 22:23:41    

++fab a écrit :

Si tu peux exposer brièvement la version haskell, je suis preneur :)


Nan, j'ai pas assez pratiqué.
En Ocaml, tu définis un variant/une union comme ça (en rouge l'évaluation du typage par l'interpréteur):
 
#type number = Int of int | Float of float | NaN;;
type number = Int of int | Float of float | NaN
 
Le symbole | est à comprendre comme "ou" (alternative).
 
Un type énuméré:
 
#type sign = Positive | Negative;;
type sign = Positive | Negative
 
 
Hop, on peut définir une addition:
 
#let add_num n1 n2 =
   match (n1, n2) with
     (Int i1, Int i2) ->
       (* Check for overflow of integer addition *)
       if sign_int i1 = sign_int i2 && sign_int(i1 + i2) <> sign_int i1
       then Float(float i1 +. float i2)
       else Int(i1 + i2)
   | (Int i1, Float f2) -> Float(float i1 +. f2)
   | (Float f1, Int i2) -> Float(f1 +. float i2)
   | (Float f1, Float f2) -> Float(f1 +. f2)
   | (Error, _) -> NaN
   | (_, Error) -> NaN;;
val add_num : number -> number -> number = <fun>
 
 
En C++, il aurait fallu surcharger la fonction add_num pour les int et les float (et ce 4 fois), et en fonction de ce qu'on lui passait en paramètre, le compilo aurait appelé la fonction qui va bien.  
Là, c'est un peu pareil, mais la grande différence est qu'on n'a pas besoin de préciser la signature des fonctions add_num. Le compilo devine tout seul ce qu'il doit générer en fonction du type de n1 et n2 donnés en entrée (inférence de types), et le mot-clé "match () with" se charge de dispatcher dans les différents cas, qui sont énumérés en-dessous (processus appelé "pattern matching" ).  
Les différents cas sont séparés par le symbole | (ou/alternative), ici:  
La fonction add_num de n1 et n2 est définie par :
  somme de 2 entiers retourne un entier ou un float en fonction du signe de n1 et n2 et de (n1+n2) (pour éviter l'overflow)
| un entier et float retourne un float
| un float et un entier retourne un float
| 2 float retourne un float
| une erreur et n'importe quel autre type (symbole _) retourne un type NaN
| vice versa retourne un type NaN
 
Non seulement le compilo n'a pas besoin qu'on lui précise le type des données en entrée (il le devine à partir du contexte), mais il vérifie qu'aucun cas n'a été oublié, et il est même capable de donner un exemple dans le cas contraire ! Bien sûr, cet exemple n'est pas très parlant car en C++, un simple cast aurait fait l'affaire, mais en Ocaml, ce genre de choses marche aussi bien avec des structures ou des classes qu'avec des types primitifs, le compilo se chargeant de la vérification du typage.
 
En définissant ainsi des variants, on peut les utiliser n'importe où dans le code, il est tjrs possible de faire du "pattern matching", et contrairement à du RTTI, il n'y a pas de risque d'erreurs ou de dégradation de perfs car tout est fait statiquement . Avec les templates C++, ce genre de choses nécessite vite de la gouroutisation de haute volée telle que pratiquée dans Boost (sans parler de la syntaxe infiniment plus complexe).
 
On peut faire des trucs marrants comme ceci:
 
#type 'a btree = Empty | Node of 'a * 'a btree * 'a btree;;
type 'a btree = Empty | Node of 'a * 'a btree * 'a btree
 
Ici 'a signifie que btree est un type paramétrable par le type a, et * est le symbole du produit cartésien.
btree est donc un template de type récursif (ici un arbre binaire).  
En empruntant la notation C++, un btree<a> est un : Empty OU un triplet (Node <a>, btree<a>, btree<a> )
(la majuscule indique la présence d'un constructeur)
 
#let rec member x btree =
   match btree with
     Empty -> false
   | Node(y, left, right) ->
       if x = y then true else
       if x < y then member x left else member x right;;
val member : 'a -> 'a btree -> bool = <fun>
 
#let rec insert x btree =
   match btree with
     Empty -> Node(x, Empty, Empty)
   | Node(y, left, right) ->
       if x <= y then Node(y, insert x left, right)
                 else Node(y, left, insert x right);;
val insert : 'a -> 'a btree -> 'a btree = <fun>
 
(rec signifie recursif, c'est dommage mais c'est nécessaire de le préciser au compilo en Ocaml)  
On vient de définir un template d'arbre binaire et 2 opérations template dessus (recherche et insertion). Et oui, c'est un langage pour gens intelligents. [:dawa] (c'est d'ailleurs à la fois sa qualité et ce qui fait son principal défaut. Vu le haut niveau d'abstraction possible, c'est pas un langage pour nOObs)

Message cité 1 fois
Message édité par el muchacho le 25-07-2006 à 17:35:12

---------------
Les aéroports où il fait bon attendre, voila un topic qu'il est bien
Reply

Marsh Posté le 25-07-2006 à 00:25:13    

Pour répondre a fab++, si on connait le type qui est théoriquement associé au void* sortant de getAttribute, ya pas vraiment de problème :s
 
maclasse* recup = (maclasse*) test.getAttribute( args... );
 
Par contre, pour récuperer automatiquement le type, cest une autre affaire...


---------------
tutos de programmation 3D :
Reply

Marsh Posté le 14-08-2006 à 13:24:22    

skelter a écrit :

Si c'etait juste ca le probleme, on peut construire une copie en castant l'adresse et en la déférencant ?
 

Code :
  1. objet a;
  2. const void * p = &a;
  3. objet b(* reinterpret_cast<const objet *>(p));



 
Oui. (j'avais des peaux d'sos dans les yeux)
 
A noter que ta solution laisse apparaitre le problème de la constness. Vu que l'on perd le type, ce n'est guère étonnant.

Reply

Marsh Posté le 14-08-2006 à 13:28:47    

el muchacho a écrit :

Nan, j'ai pas assez pratiqué.


dommage. Je vais aller apprendre Haskell comme un grand :/
 

el muchacho a écrit :

En Ocaml, tu définis un variant/une union comme ça (en rouge l'évaluation du typage par l'interpréteur):
[...]


(merci pour la bonne lecture)

Reply

Marsh Posté le    

Reply

Sujets relatifs:

Leave a Replay

Make sure you enter the(*)required information where indicate.HTML code is not allowed