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

C++ Discussion :

un cast cobditionel...


Sujet :

C++

  1. #1
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut un cast cobditionel...
    salut a tous, j'aimerais savoir comment realiser un cast conditionel en c++. Je m'explique, ma fonction reçoit un pointeur style LAPARAM.
    Ce pointeur peur designer un classe A ussi bien qu'une classe B derivée de A, classe C derivée de A, classe D derivée de A...

    Si je cast le pointeur en A pas de pb pour avoir acces aux methodes commune a A, B, C, D...... Mais comment faire dans le cas ou c'est une instance de B de C ou de D, comment savoir ce que represente le LPARAM ??
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    static BOOL CALLBACK dlgProc (HWND hWnd, UINT wMsg, WPARAM wParam,LPARAM lParam) 
    {
     
    [color=red]  si lParam est de la classe C alors
    C* c = (C*) lParam
     
      si lParam est de la classe B alors
    B* b = (B*) lParam
    ......[/color]	
    }
    En gros c'est l'equivalent de instanceof() de java pour ceux qui connaissent

  2. #2
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    C'est en général à éviter en C++. Fais une recherche sur ce forum avec "downcastnig" pour voir pourquoi.

    On préferera toujours passer par le polymorphisme dynamique (héritage et fonctions membres virtuelles) ou le polymorphisme statique (templates).

  3. #3
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut d'accord mais...
    je veux bien faire du polymorphysme mais pour ça il faut avoir des objets sous la main (d'apres ce que j'ai pu comprendre)
    Mon problem et que ma fonction est une CALLBACK static, et je lui passe des objets au lancement.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    [color=blue]CDialog, ou CDialogA, ou CDialogB....[/color] * dlg;
     
    DialogBoxParam(CDialog::hInstance,MAKEINTRESOURCE(((CDialog*)(lParam))->lpTemplateId), CDialog::hwndMain,CDialog::dlgProc,(LPARAM)(dlg));
    Donc danc la CALLBACK c 'est dur de savoir qui a été créé, et il me vien aussi une question, si je cast en classe de base le polymorphysme est foutu, mon pointeur ne siat plus (ou pas) qu'il est issu d'une classe specialisant la calsse mere ??

  4. #4
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut Je l'ai merci !
    Citation Envoyé par Asarnil
    alors tu fais un tableau de pointeur vers la classe parente

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
     
    class parent {..........};
    class fils : public parent {.........};
    class fille : public parent {........};
     
    . . .
     
    vector <parent*> tab;
    tab.push_back(new fils);
    tab.push_back(new fille);
    apres pour utiliser les objets de ton tableau, si tu sais ce que c'est : static_cast, sinon dynamic_cast

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    static_cast<fils*>(tab[0])->methode();
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
    fille* pt;
    pt = dynamic_cast<fille*>(tab[1]); // je tente la conversion
    if (pt != NULL) pt->methode(); // ca marche, c'est bien une fille
    C'est excatement ce que je veux faire merci encore, j'ai bien compris que c'etait moche comme truc mais il me semble que j'ai pas du tout le choix dans mon cas...

  5. #5
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut uen question...
    J'ai regarder les FAQ et je trouve ça :
    class A
    {
    public:
    void F1() { cout << "A::F1()\n"; }
    virtual void F2() { cout << "A::F2()\n"; }
    };

    class B : public A
    {
    public:
    void F1() { cout << "B::F1()\n"; }
    void F2() { cout << "B::F2()\n"; }
    };

    int main()
    {
    A a;
    a.F1(); // affiche "A::F1()"
    a.F2(); // affiche "A::F2()"

    B b;
    b.F1(); // affiche "B::F1()"
    b.F2(); // affiche "B::F2()"

    // copie non polymorphique
    a = b;
    a.F1(); // affiche "A::F1()"
    a.F2(); // affiche "A::F2()"

    // utilisation polymorphique de B (par pointeur)
    A * pa = &b;
    pa->F1(); // affiche "A::F1()"
    pa->F2(); // affiche "B::F2()" <-- grace à virtual

    // utilisation polymorphique de B (par référence)
    A & ra = b;
    ra.F1(); // affiche "A::F1()"
    ra.F2(); // affiche "B::F2()" <-- grace à virtual
    }
    la ligne
    // utilisation polymorphique de B (par pointeur)
    A * pa = &b;
    pa->F1(); // affiche "A::F1()"
    pa->F2(); // affiche "B::F2()" <-- grace à virtual
    m'interresse plus particulierement mais la j'aiun probleme !
    Si je reprends mon cas

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    static BOOL CALLBACK dlgProc (HWND hWnd, UINT wMsg, WPARAM wParam,LPARAM lParam) 
    { 
       CDialog * pDlg = NULL; 
       pDlg = (CDialog *) lParam;
       if(!pDlg->isHandled(hWnd,wMsg,wParam,lParam)) 
          return DefWindowProc(hWnd,wMsg,wParam,lParam); 
       return TRUE; 
    }
    je vois mal coment faire une copie "polymorphique par pointeur" car mon pointeur est reçu comme un LPARAM et pas un pointeur de classe

    Alors voilà comment qu'on fait maintenant ?

  6. #6
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Si tu manipules une hiérarchie de classes toutes issues (publiquement) de A, pourquoi ne pourrais-tu pas utiliser le polymorphisme ? Tu transformes ton LPARAM en A* et après tu fais marcher les fonctions virtuelles.

    Le downcasting est ici inutile je pense.

    Tu peux préciser le contexte de cette manip ? Que représentent ces classes plus exactement ?

  7. #7
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    J'ai fusionné les sujets, merci de ne pas ouvrir 2 topics pour le même problème (surtout si c'est pour poster les mêmes messages dans les 2).



    je vois mal coment faire une copie "polymorphique par pointeur" car mon pointeur est reçu comme un LPARAM et pas un pointeur de classe
    Ben tu castes sauvagement ton LPARAM en A*. De toute façon un LPARAM en l'état c'est presque pas utilisable, faut forcément le caster. C'est un peu comme un void*.

  8. #8
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut effectivement...
    Merci pour la fusion je savais pas comment faire pour regrouper les deux sujet promis je refait plus


    tu as raison c'est d'ailleurs ce que j'ai fait mais il y a un probleme sur le cast en fait je te donne toutes les billes.
    En gros je recode les CDialog pour un telephone portable (pas de MFC sur les OS windows mobile) alors j'essais de refaire une classe CDialog qui ressemble bcp a celle de MFC.

    J'ai une fonction CALLBACK pour les messages definie en static dans la classe mere et des fonctions virtuel pour les traitements (pour justement utilisé le polymorph.)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    static BOOL CALLBACK dlgProc (HWND hWnd, UINT wMsg, WPARAM wParam,LPARAM lParam) 
    {
    	CDialog * pDlg = (CDialog *) lParam;
     
    	return pDlg->isHandled(hWnd,wMsg,wParam,lParam);	
    }
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    virtual BOOL isHandled(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam);
    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
     
    BOOL CDialog::isHandled(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
    {	
    	switch(wMsg)
    	{
    		case WM_INITDIALOG :
    			return this->OnInitDialog(hWnd,wMsg,wParam,lParam);
    		break;
     
    		case WM_COMMAND :
    			return this->OnCommand(hWnd,wMsg,wParam,lParam);
    		break;
     
    		default :
    			return DefWindowProc(hWnd,wMsg,wParam,lParam);
    		break;
    	 }
    }
    Bien sur les fonctions de traitement style OnCommand sont virtuelles pour et certaines virtuelles pure.

    Mais comme tu vois dans la CALLBACK je retrouve le pointeur a chaque fois depuis le LPARAM.
    Ceci ne pose pas de probleme si la fonction isHandled n'est pas virtuelle, le pointeur est toujours retrouvé corretement, mais si je passe isHandled en virtuel certains messages perdent le LPARAM (ou plutot le modifie) et resultat ça plante .

    C'est pour cela que le dynamic_cast m'interresse, il me permettrais de savoir si le LAPRAM est valide ou non (en terme de pointeur sur classe)

    Alors voilà, je cherche une solutuion elegante au probleme et c'est vrai que "virtuel" c'est jolie mais sans moyen de controle sur le LPARAM je vois pas comment l'utilisé , alors si tu as une idée je suis preneur

  9. #9
    Membre habitué Avatar de PINGOUIN_GEANT
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    149
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 149
    Points : 155
    Points
    155
    Par défaut
    un truc que je trouve étonnant dans la conception et qui m'amène à cette question de néophyte : cela se fait beaucoup de manipuler des types/classes représentant des pointeurs de classes ? pourquoi ne pas manipuler directement la classe elle-même ?
    " Tout homme est digne d'un parapluie." Stavroguine dans Les Démons de Dostoïevski.

  10. #10
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    mais si je passe isHandled en virtuel certains messages perdent le LPARAM (ou plutot le modifie) et resultat ça plante
    Une fois que tu as casté ton LPARAM en CDialog* tu n'as plus besoin de ce dernier a priori, il peut être modifié non ? Tu peux préciser un peu plus cet aspect (voire donner un exemple concret) ?

  11. #11
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut Un exemple....
    Passons direct a ce qui ##''"'"é'$£¤, typiquement je fait un init de d'une boite de dialogue :

    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
    29
    30
    31
    32
    33
    34
    BOOL CDialog::OnInitDialog(HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
    {
    	//MessageBox(hWnd,TEXT("init"),TEXT("Info"),MB_ICONINFORMATION);
     
    	// Specify that the dialog box should stretch full screen
    	SHINITDLGINFO shidi = {0};
     
    	shidi.dwMask  = SHIDIM_FLAGS;
    	shidi.dwFlags = SHIDIF_SIZEDLGFULLSCREEN ;
    	shidi.hDlg    = hWnd;
     
    	if(!SHInitDialog(&shidi))
    	{
    		MessageBox(NULL,TEXT("error"),TEXT("Cap"),MB_OK | MB_ICONASTERISK);
    		return FALSE;
    	}
     
    	// Create menubar
    	SHMENUBARINFO mbi = {0};
     
    	mbi.cbSize = sizeof(SHMENUBARINFO);
    	mbi.hwndParent = hWnd;
    	mbi.nToolBarId = this->menuBarId;//******************* 
    	mbi.hInstRes = CDialog::hInstance;
     
    	// If we could not initialize the dialog box, return an error
    	if (!SHCreateMenuBar(&mbi)) {
    		MessageBox(NULL,TEXT("Menubar failed"),TEXT("Cap"),MB_OK | MB_ICONASTERISK);
    		DestroyWindow (hWnd);
    		return FALSE;
    	}	
     
    	return TRUE;
    }
    C'est le code appelé lors de la creation de la boite, tous ce passe bien jusque la :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
     
    if(!SHInitDialog(&shidi))
    Cette fonction renvoi in WM_INITDIALOG sans rien dire a personne (merci le debugger) result dans la CALLBACK le lParam n'est plus bon SHInitDialog(&shidi) doit mettre un truc a la con dedans !
    Ce qui fait que dans dans ce qui devrais etre le deuxieme passage tout plante !
    Alors ya deux choses qui m'etonne, avec le meme code et la fonction isHandled (Cf post precedent) declaree en "normale" ça passe, mais si je specifie "virrtual" pour isHandled ça crash !
    Alors a cour d'idee j'explore les possibilité de plus haut niveau (WTL)

    Citation Envoyé par PINGOUIN_GEANT
    un truc que je trouve étonnant dans la conception et qui m'amène à cette question de néophyte : cela se fait beaucoup de manipuler des types/classes représentant des pointeurs de classes ? pourquoi ne pas manipuler directement la classe elle-même ?
    En fait je n'ai pas acces a la calasse j'ai une fonctionn static de classe qui gere les messages de fenetre, une fonction :

    static BOOL CALLBACK dlgProc (HWND hWnd, UINT wMsg, WPARAM wParam,LPARAM lParam)
    Et lParam c'et pas moi qui choisi c'est un long * (un pointeur quoi)...

  12. #12
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Cette fonction renvoi in WM_INITDIALOG sans rien dire a personne (merci le debugger) result dans la CALLBACK le lParam n'est plus bon SHInitDialog(&shidi) doit mettre un truc a la con dedans !
    Ce qui fait que dans dans ce qui devrais etre le deuxieme passage tout plante !
    Le paramètre LPARAM (comme tous les autres) seront différents à chaque appel de ta fonction de callback, je ne comprends pas trop ce que tu veux dire . D'ailleurs oui, ça me paraît bizarre que tu récupères ton pointeur via le LPARAM (comment tu le passes ?), puisque celui-ci sera rempli avec des données spécifiques au message envoyé. Habituellement c'est le paramètre HWND qui sert à identifier le contrôle / fenêtre qui est concerné par le message.

  13. #13
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut coment je le passe....
    Je le cast en lParam et apres je le passe a uen fonction de creation de fenetre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    DialogBoxParam(CDialog::hInstance,MAKEINTRESOURCE(((CDialog*)(lParam))->lpTemplateId),CDialog::hwndMain,CDialog::dlgProc,lParam);
    Syntax

    INT_PTR DialogBoxParam( HINSTANCE hInstance,
    LPCTSTR lpTemplateName,
    HWND hWndParent,
    DLGPROC lpDialogFunc,
    LPARAM dwInitParam
    );
    Parameters

    hInstance
    [in] Handle to the module whose executable file contains the dialog box template.
    lpTemplateName
    [in] Specifies the dialog box template. This parameter is either the pointer to a null-terminated character string that specifies the name of the dialog box template or an integer value that specifies the resource identifier of the dialog box template. If the parameter specifies a resource identifier, its high-order word must be zero and its low-order word must contain the identifier. You can use the MAKEINTRESOURCE macro to create this value.
    hWndParent
    [in] Handle to the window that owns the dialog box.
    lpDialogFunc
    [in] Pointer to the dialog box procedure. For more information about the dialog box procedure, see DialogProc.
    dwInitParam
    [in] Specifies the value to pass to the dialog box in the lParam parameter of the WM_INITDIALOG message.
    Je crois pas trop avoir le chois de la methode de passage de la fenetre, alors si tu as une idee...

  14. #14
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    Ok, c'est donc seulement lorsque le message sera WM_INITDIALOG que ton LPARAM sera un pointeur sur ta fenêtre. Donc ton code est incorrect .

    Pour la suite, ce que tu peux faire c'est garder en static dans CDialog un map<HWND, CDialog*> associant chaque HWND à sa fenêtre. Ca te permettra de retrouver ta fenêtre très simplement dans ta fonction de callback, d'après son hwnd.

  15. #15
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut BA VI 9A MORCHE PO
    Effeticvement il faut memoriser les HWND mais j'ai pas la moundre idee de comment faire tu peux expliquer un pil plus les template <trux , muche > ??

  16. #16
    Rédacteur
    Avatar de Laurent Gomila
    Profil pro
    Développeur informatique
    Inscrit en
    Avril 2003
    Messages
    10 651
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France, Moselle (Lorraine)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Avril 2003
    Messages : 10 651
    Points : 15 920
    Points
    15 920
    Par défaut
    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
    #include <map>
    #include <windows.h>
     
    class CDialog
    {
    public :
     
        static BOOL CALLBACK dlgProc (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
        {
            if (wMsg == WM_INITDIALOG)
                Dialogs[hWnd] = reinterpret_cast<CDialog*>(lParam);
     
            return Dialogs[hWnd]->isHandled(hWnd, wMsg, wParam, lParam);
        }
     
    private :
     
        static std::map<HWND, CDialog*> Dialogs;
    }

  17. #17
    Membre régulier
    Profil pro
    Inscrit en
    Juin 2004
    Messages
    228
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2004
    Messages : 228
    Points : 102
    Points
    102
    Par défaut alors la !!!
    Je connaissait pas le truc, masi je dois sir je suis bleuffé un truc presque comme les fameuses hashtable de java.....
    waouuu merci encore ce sera tous pour mon problème

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [VB.NET] Cast d'une tablecell
    Par Pari dans le forum ASP.NET
    Réponses: 6
    Dernier message: 05/05/2004, 15h58
  2. Probleme CAST
    Par cedric31 dans le forum SQL
    Réponses: 2
    Dernier message: 16/02/2004, 10h46
  3. CAST ou autre ?
    Par 74160 dans le forum Requêtes
    Réponses: 2
    Dernier message: 10/07/2003, 15h00
  4. CAST DATETIME ----> SMALLDATETIME
    Par Guizz dans le forum MS SQL Server
    Réponses: 2
    Dernier message: 26/06/2003, 12h07
  5. traduction en delphi "reinterpreted cast"
    Par Chupakabra dans le forum Langage
    Réponses: 3
    Dernier message: 13/02/2003, 15h49

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