IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

MFC Discussion :

[MFC] CArray et classe dérivée?


Sujet :

MFC

  1. #1
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Par défaut [MFC] CArray et classe dérivée?
    Re Salut...

    J'ai de nouveau un pitit problème avec le template CArray...
    J'ai donc un CArray<CClass1,Cclass1&> m_tabClass1

    Ma classe CClass1 possède en fait des classes filles CClassF1,CClassF2, etc...

    Pour ajouter un élément, j'écris :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    CClassF1 *pItem; 
    pItem=new CClassF1();
    m_tabClass1.Add(*pItem);
    Déjà en faisant ça, je m'apercois qu'il passe deux fois par le constructeur de CClass1... Ce qui voudrait dire que le "Add" duplique mon objet que j'ai créé la ligne d'au dessus?

    Par ailleurs, et c'est mon problème, j'ai l'impression qu'il caste mon objet CClassF1 en CClass1 pour le rajouter dans le tableau... du coup, quand je récupère un élement du tableau, il est uniquement de type CClass1...

    Comment faire sans modifier mon CArray? (en gardant : CArray<CClass1,Cclass1&>)

    Merci d'avance...

  2. #2
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Déjà en faisant ça, je m'apercois qu'il passe deux fois par le constructeur de CClass1... Ce qui voudrait dire que le "Add" duplique mon objet que j'ai créé la ligne d'au dessus?
    Il est probable que c'est une copie qui est stockée, sinon, on ne pourrait pas mettre dans le tableau des objets construits comme objets locaux ou comme objets temporaires. Dans ce cas, si le tableau est déclaré comme tableau de CClass1 , seule la "partie" CClass1 de l'objet peut être copiée puisque le CArray ne peut pas savoir le type complet de l'objet.
    Comment faire sans modifier mon CArray?
    Je ne sais pas. La solution consisterait à stocker dans le tableau un pointeur sur la classe de base ce qui préserverait le polymorphisme à condition d'allouer les objets dynamiquement (ce qui est le cas de l'exemple)

  3. #3
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Par défaut
    Oui, en effet, je ne sais pas comment faire en gardant ma structure actuelle du CArray.

    J'ai donc modifié en CArray<CClass1*,Cclass1*> et ce sont maintenant des pointeurs qui sont stockés, et le polymorphisme peut s'appliquer...

    Cependant, lorsque je veux sérialiser ce template, lors de la relecture (ar.IsLoading()==TRUE), je suis obligé de recréer l'objet d'abord, de vérifier sa classe puis d'y appliquer le "bon" type...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    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
     
    template <> static void AFXAPI SerializeElements <CClassP*> 
    							   (CArchive& ar, CClassP** pItem, int nCount )
     
    {
    if (ar.IsLoading())
    		{
    			char pb[1];
    			ar.Read(pb,1);
    			if (pb[0]==1) { (*pItem)=new CClassF1(); }
    			if (pb[0]==2) { (*pItem)=new CClassF2(); }
    			if (pb[0]==3) { (*pItem)=new CClassF3(); }
    			if (pb[0]==4) { (*pItem)=new CClassF4(); }
    			if (pb[0]==5) { (*pItem)=new CClassF5(); }
    			(*pItem)->Serialize( ar );
    		}
    		else
    		{
    			char pb[1];
    			if ((*pItem)->IsKindOf(RUNTIME_CLASS(CClassF1))) {pb[0]=1;}
    			if ((*pItem)->IsKindOf(RUNTIME_CLASS(CClassF2))) {pb[0]=2;}
    			if ((*pItem)->IsKindOf(RUNTIME_CLASS(CClassF3))) {pb[0]=3;}
    			if ((*pItem)->IsKindOf(RUNTIME_CLASS(CClassF4)))  {pb[0]=4;}
    			if ((*pItem)->IsKindOf(RUNTIME_CLASS(CClassF5))) {pb[0]=5;}
    			ar.Write(pb,1);
    			(*pItem)->Serialize( ar );
     
    		}
    Evidemment cela fait un peu, beaucoup bricolage (...) mais avec un CArray de pointeurs, y-a-t-il une méthode plus élégante pour le sérialiser?
    Et si je garde un CArray d'objet, ne peut-on vraiment pas appliquer le polymorphisme?

    Autant de questions dont mahleureusement, je ne trouve pas la solution...Merci d'avance pour toute aide

  4. #4
    Expert confirmé
    Avatar de diogene
    Homme Profil pro
    Enseignant Chercheur
    Inscrit en
    Juin 2005
    Messages
    5 761
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Enseignant Chercheur
    Secteur : Enseignement

    Informations forums :
    Inscription : Juin 2005
    Messages : 5 761
    Par défaut
    Il doit falloir surcharger Serialize dans les classes dérivées. Dans la version surchargée pour l'écriture, écrire le bon identificateur (pb), appeler Serialize de la classe de base et ajouter la partie spécifique à la classe dérivée. Normalement, le polymorphisme évitera de tester le bon type de la classe à sérialiser et on aura simplement
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
     else (*pItem)->Serialize( ar )
    Pour la partie lecture, je ne vois pas de simplification notable

  5. #5
    mat.M
    Invité(e)
    Par défaut
    ??? en appelant les méthodes de "serialization" il n'y a pas besoin de faire de s new

    Sinon si CArray pose trop de problèmes prendre CObArray ou CObList

  6. #6
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Par défaut
    Euh... c'est sûr? Même avec CArray<CClass1*,Cclass1*> ?

    Si le CArray contient des pointeurs, à la relecture, que fait-il pour chaque élément? Il crée les pointeurs uniquement mais ces pointeurs ne pointent vers aucun objet non?

    Alors si on écrit :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    if (ar.IsLoading())
          {
             (*pItem)->Serialize( ar );
    On ne peut pas faire le ->Serialize non? En tout cas, lorsque je ne crée pas d'objet au préalable, il m'informe d'une "unhandle exception"...

    Désolé si je suis à côté de la plaque, mais si effectivement, il n'y a pas besoin de créer d'objets, comment faire pour que cela fonctionne?

  7. #7
    Rédacteur
    Avatar de bigboomshakala
    Homme Profil pro
    Consultant Web .NET
    Inscrit en
    Avril 2004
    Messages
    2 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant Web .NET
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2004
    Messages : 2 077
    Par défaut
    je confirme. en procédant ainsi la sérialisation se passe bien, mais la désérialisation provoque une erreur.

    je n'ai pas encore eu trop le temps d'y penser. je regarderais ça demain. j'espère y apporter une réponse.

  8. #8
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Par défaut
    Ok! En tout cas, merci à tous ceux qui essayer d'aider

  9. #9
    Rédacteur
    Avatar de bigboomshakala
    Homme Profil pro
    Consultant Web .NET
    Inscrit en
    Avril 2004
    Messages
    2 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant Web .NET
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2004
    Messages : 2 077
    Par défaut
    bon ben si je ne suis pas à côté de la plaque alors c'est très simple.

    une classe User contient un CArray<ClassMere*,ClassMere*> tab

    pour sérialiser tab, on implémente la méthode SerializeElement<ClassMere*> dans ClassMere.h (User y aura accès, puisque c'est dans le .h)

    User veut pouvoir utiliser tab pour stocker des pointeurs sur des classes filles de ClassMere. Pour cela il devrait suffir d'implémenter dans les classes filles (dans le .h des classes filles) la méthode SerializeElement<ClassFille*>

    (je n'ai pas testé avec une classe mère et des classes filles. j'ai seulement testé mon implémentation de SerializeElement<UneClasse*>)

    pour chaque classe on implémentera de la façon suivante
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    template <>
    static void AFXAPI SerializeElements <ClasseX*> (CArchive& ar,ClasseX** pItem,int nCount)
    {
        for ( int i = 0; i < nCount; i++, pItem++ )
    	{
    		if (ar.IsLoading())
    			(*pItem) = new ClasseX();
     
            (*pItem)->Serialize( ar );    
    	}
    }
    avec ClasseX à remplacer par ClassMere ou une ClassFille.

    et lorsqu'on utilisera la CArray, il faut garder à l'esprti que lors de la destruction du CArray, les pointeurs qu'il contient sont détruits MAIS PAS LES VARIABLES POINTEES !

    donc il faudra libérer la mémoire au moment adéquat.

    exemple de sérialisation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    	CArray<ClasseX*,ClasseX*> tab;
    ...
        {
            CFile File;    
            if(File.Open("MyArchive.arc", CFile::modeCreate | CFile::modeWrite ))
            {
                CArchive ar( &File, CArchive::store);
                tab.Serialize(ar);
            }
        }
    exemple de désérialisation
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
        CArray<ClasseX*,ClasseX*> tab2;
        CFile File;    
        if(File.Open("MyArchive.arc", CFile::modeRead ))
        {
            CArchive ar( &File, CArchive::load);
            tab2.Serialize(ar);
        }
    et dans les deux cas, libérer la mémoire lorsque le CArray n'est plus utile
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    	for (int i = 0; i < tab.GetSize(); i++) delete tab[i];
    ceci pouvant par exemple être fait dans le destructeur de la classe mère (et donc les classes filles héritent de ce comportement)

  10. #10
    Rédacteur
    Avatar de bigboomshakala
    Homme Profil pro
    Consultant Web .NET
    Inscrit en
    Avril 2004
    Messages
    2 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant Web .NET
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2004
    Messages : 2 077
    Par défaut
    hmm bon ce matin en relisant je me rend compte que dans notre cas ça ne va pas marcher parce que le CArray est toujours déclaré comme contenant des ClassMere*. donc la fonction SerializeElement appelée sera toujours celle comportant le new ClassMere()...

  11. #11
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Par défaut
    Oui en effet, j'ai testé et c'est toujours le SerializeElement de la classe parent qui est appelé...

    Donc si je résume :
    - si j'utilise un template du type CArray<CClass1,CClass1&>, je ne peux mettre que des objets parents ds le CArray...

    -si j'utilise un template du type CArray<CClass1*,CClass1*>, il faut passer par une "manip" pour créer dynamiquement les objets et "choisir" parmi les classes filles lors du Serialize en lecture...
    Evidemment, ça marche, j'ai fait comme ça, mais d'un point de vue "propreté du code", ce n'est peut-etre pas optimal... je reste preneur de toute solution proposée

  12. #12
    Rédacteur
    Avatar de bigboomshakala
    Homme Profil pro
    Consultant Web .NET
    Inscrit en
    Avril 2004
    Messages
    2 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant Web .NET
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2004
    Messages : 2 077
    Par défaut
    au fait, le CArray contient-il des pointeurs sur objets de meme type (que des Mere*, ou que des Filles1*, Fille2* ...) ?

    si oui, le programmeur sait-il quelle est ce type exact ?

    si les réponses sont 'oui' et 'oui', alors j'ai peut-être une solution en remplaçant le CArray par un std::vector
    sinon je ne vois pas mieux que ce que tu as.


  13. #13
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Par défaut
    Citation Envoyé par bigboomshakala
    au fait, le CArray contient-il des pointeurs sur objets de meme type (que des Mere*, ou que des Filles1*, Fille2* ...) ?

    si oui, le programmeur sait-il quelle est ce type exact ?

    si les réponses sont 'oui' et 'oui', alors j'ai peut-être une solution en remplaçant le CArray par un std::vector
    sinon je ne vois pas mieux que ce que tu as.

    Hum,... pas compris ta question...
    CMère est dérivée de CObject et CFilleX de CMère, le CArray ne contient que des pointeurs vers ces classes.

  14. #14
    Rédacteur
    Avatar de bigboomshakala
    Homme Profil pro
    Consultant Web .NET
    Inscrit en
    Avril 2004
    Messages
    2 077
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 45
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Consultant Web .NET
    Secteur : Finance

    Informations forums :
    Inscription : Avril 2004
    Messages : 2 077
    Par défaut
    Citation Envoyé par TigreRouge
    Hum,... pas compris ta question...
    tu as un CArray<CMère *,CMère *> tab

    lorsque tu le remplis, le type réel des objets qu'il contient est-il le meme pour tous les élements, ou pas ?

    CAS 1 : tous les memes

    • (*tab[0]) de type CFille2
      (*tab[1]) de type CFille2
      ...
      (*tab[n]) de type CFille2


    CAS 2 : pas forcément tous les memes

    • (*tab[0]) de type CMere
      (*tab[1]) de type CFille1
      (*tab[1]) de type CFille2
      (*tab[1]) de type CFille1
      (*tab[1]) de type CFille1
      ...
      (*tab[n]) de type CMere


    si on est dans le cas 1 et si tu sais dans le code de quel type réel il s'agit, alors j'ai peut etre une soluce

    si on est dans le cas 2, alors je n'ai pas mieux que ce que tu as déjà

  15. #15
    Membre confirmé
    Inscrit en
    Juin 2004
    Messages
    79
    Détails du profil
    Informations forums :
    Inscription : Juin 2004
    Messages : 79
    Par défaut
    cas 2 malheureusement
    Merci quand même pour tes éclairages

Discussions similaires

  1. [Débutant][MFC] CArray
    Par gwendo dans le forum MFC
    Réponses: 2
    Dernier message: 21/03/2005, 10h00
  2. [MFC]creer une classe derivé de CWinThread
    Par psyjess dans le forum MFC
    Réponses: 2
    Dernier message: 18/03/2005, 14h23
  3. [MFC] surcharger une classe
    Par exter666 dans le forum MFC
    Réponses: 9
    Dernier message: 16/03/2005, 00h53
  4. Réponses: 6
    Dernier message: 28/02/2005, 12h10
  5. Déterminer le type d'une class dérivée
    Par LDDL dans le forum MFC
    Réponses: 3
    Dernier message: 10/12/2004, 17h36

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo