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

Discussion :

Échec de cast d'une classe fille de QObject en QObject

  1. #1
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 125
    Points : 57
    Points
    57
    Par défaut Échec de cast d'une classe fille de QObject en QObject
    Bonjour,

    Je peine depuis un beau bout de temps à trouver ce qui ne va pas avec un cast d'une classe fille de QObject en Qbject.

    Plus en détail, j'ai un classe A qui hérite de QObject et de B. La classe a contient entre autres une map QMap<QString, QPropertyAnimation*> (je la cite car c'est avec elle où ça ne va pas). J'ai connecté le signal de destruction de A à un slot qui tente d'accéder à la map par son getter. Et c'est que ça chauffe : mon cast (avec static_cast) marche (pointeur non NULL) mais la map est inaccessible. Pourquoi ?

    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
     
         class B
         {
             ...
         };
     
         class A : public QObject, public B
         {
               Q_OBJECT
     
               public:
                    A() : m_propertiesAnimation("prop", new QPropertyAnimation), B()
                    {
                    }
     
                    QMap<QString, QPropertyAnimation*> getPropertiesAnimation()
                    {
                           return m_propertiesAnimation;
                    }
     
               private:
                       QMap<QString, QPropertyAnimation*> m_propertiesAnimation;  
         };
    La connexion du signal de destruction, je l'a fais dans une autre classe C ainsi :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
     
               A * variable_A = new A();
               connect(variable_A, SIGNAL(destroyed(QObject*)),
                    this, SLOT(remove(QObject*)), Qt::UniqueConnection);
    Le slot dans lequel la map est inaccessible (les autres propriétés de ma classe ne le sont pas par contre) est :
    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
     
    void C::remove(QObject *ai_item)
    {
        A * a0 = qobject_cast<A*>(ai_item);   // CE CAST NE MARCHE PAS => NULL
        if (a0 != NULL)
        {
            qWarning() << a0->getPropertiesAnimation();
        }
     
       A * a1 = static_cast<A*>(ai_item);   // CE CAST MARCHE
        if (NULL != a1)
        {
             qWarning() << a1->getPropertiesAnimation(); // ERREUR de segmentation
        }
    }
    Merci pour toute aide !

  2. #2
    Membre averti

    Homme Profil pro
    Inscrit en
    Février 2010
    Messages
    243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2010
    Messages : 243
    Points : 398
    Points
    398
    Par défaut
    Est-ce que tu est sûr que ton objet est toujours vivant à la réception de ton signal ?

    Tu n'es pas dans un thread par hasard ?

    Que se passe-t-il si tu utilises une connection directe :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    connect( ... , Qt::Directconnection)

  3. #3
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 125
    Points : 57
    Points
    57
    Par défaut
    L'objet est vivant puisque le pointeur reçu n'est pas NULL. C'est le cast qui cause problème je pense !

    Sinon, j'ai utilisé Directconnection mais sans succès, le static_cast marche mais la map est inaccessible !

    Merci pour réaction.

    Autre chose, en mode debug, j'ai une erreur de : RTTI symbol not found for class 'QObject'. dès que je tente d'accéder à la map !

  4. #4
    Membre averti

    Homme Profil pro
    Inscrit en
    Février 2010
    Messages
    243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2010
    Messages : 243
    Points : 398
    Points
    398
    Par défaut
    Citation Envoyé par hisoft Voir le message
    Autre chose, en mode debug, j'ai une erreur de : RTTI symbol not found for class 'QObject'. dès que je tente d'accéder à la map !
    Ah ben oui ! C'est normal

    Ce qu'il se passe c'est que lors de la destruction, les destructeurs sont appellés en ordre inverse de la construction.

    Donc le destructeur de A est appelé : il détruit la map !
    Ensuite celui de QObject (ou de B mais peu d'importance) est appellé : émission du signal destroyed(). Mais A n'existe plus, donc il est impossible d'accéder la map de l'objet. Seulement les fonctions de QObject seront accèssibles

  5. #5
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 125
    Points : 57
    Points
    57
    Par défaut
    Je ne te suis pas là. Je capte le signal émis par A lorsque A est sur le point d'être détruit (mais pas encore). Le slot que j'exécute lors de l'émission du signal doit donc trouver A non encore détruit puisque c'est ça l'utilité du destroyed() de A !

    Donc A ne doit être détruit qu'à la fin de l'exécution du slot. D'ailleurs, si tel n'était pas le cas, les autres variables membres de A seraient également perdues !

  6. #6
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 125
    Points : 57
    Points
    57
    Par défaut
    Tu as effectivement raison : j'ai créé un destructeur bidon pour A et il est bien appelé avant le slot. Mais c'est quoi alors la solution ?

  7. #7
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 125
    Points : 57
    Points
    57
    Par défaut
    C'est bon j'ai trouvé une solution pour contourner le problème. Vu que A a accès à C et que c'est dans C que le slot figure, je déporte tout simplement le traitement se trouvant dans le slot de C vers le destructeur de A et du coup ma map n'est pas encore supprimée !

    Sinon, j'aurais bien aimer savoir s'il y a un autre moyen de le faire car là c'est le lien entre A et C qui me sauve. Et s'il y en avait pas et qu'on ne devait pas en créer, quelle serait la solution ?

    Merci

  8. #8
    Membre averti

    Homme Profil pro
    Inscrit en
    Février 2010
    Messages
    243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2010
    Messages : 243
    Points : 398
    Points
    398
    Par défaut
    Pour moi ce genre de problème vient d'un problème de conception à la base.

    Je ne sais pas ce que C est censé faire à la destruction de A, mais certainement pas aller fouiner dans les données des classes qui héritent de A...

    En déplaçant ta map, tu obtiens probablement une meilleure conception de tes classes.

    La on quitte un problème Qt ou même C++ pour de l'orienté objet, je vais pas trop m'étendre :p

  9. #9
    Membre du Club
    Inscrit en
    Juin 2008
    Messages
    125
    Détails du profil
    Informations forums :
    Inscription : Juin 2008
    Messages : 125
    Points : 57
    Points
    57
    Par défaut
    Citation Envoyé par ness522 Voir le message
    Pour moi ce genre de problème vient d'un problème de conception à la base.

    Je ne sais pas ce que C est censé faire à la destruction de A, mais certainement pas aller fouiner dans les données des classes qui héritent de A...

    En déplaçant ta map, tu obtiens probablement une meilleure conception de tes classes.

    La on quitte un problème Qt ou même C++ pour de l'orienté objet, je vais pas trop m'étendre :p
    Non du tout. Ce n'est pas un problème de conception. Juste peut être que tu n'y as pas encore été confronté !
    Mais pour t'éclairer un peu sur la chose : la classe C est en fait un AnimationManager qui ne doit s'occuper que des animations qu'on lui fournit !
    La classe A est un objet graphic qui gère une map de QPropertyAnimation des chacune de ses propriétés.

    Le but est que quand l'item graphique est détruit que l'animation manager le sache pour détruire la QPropertyAnimation qu'il gère ! Et la conception veut que chaque item graphique gère lui même ses QPropertyAnimation et que le manager ne fasse que de la lecture ...

    Mais merci quand même pour l'intérêt porté à mon problème !

  10. #10
    Membre averti

    Homme Profil pro
    Inscrit en
    Février 2010
    Messages
    243
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations forums :
    Inscription : Février 2010
    Messages : 243
    Points : 398
    Points
    398
    Par défaut
    Et le C::add( ... ) est appelé où ?

    Si c'est dans le constructeur de A ou dans une autre fonction de A, ça me semblerait plus logique d'appeller C::remove depuis le destructeur de A.
    Pourquoi se connecter sur le signal destroyed du parent, caster le pointeur etc... ça me semble compliqué.

    Autre solution, ajouter un signal "Adestroyed" à ta classe A, l'émettre toi même dans le desctructeur de A. Et connecter ce signal et non celui de QObject. Mais bon ça revient fort au même :p

  11. #11
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 617
    Points
    15 617
    Par défaut
    Bonjour

    Plusieurs remarques, dans l'ordre où je les trouves dans les posts

    mon cast (avec static_cast) marche (pointeur non NULL)
    L'objet est vivant puisque le pointeur reçu n'est pas NULL
    Non
    static_cast ne fait pas de vérification de type à l'exécution donc il ne vérifie pas si ton pointeur pointe vers quelque chose qui "existe". Delete supprime juste les objets mais ne modifie pas les pointeurs.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    A* a = new A();
    delete a;
    assert(a == NULL); // erreur
    Et effectivement, comme le dis ness ensuite, ton objet A n'est plus (totalement) valide.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A() : m_propertiesAnimation("prop", new QPropertyAnimation), B() {}

    C'est bien d'utiliser les listes d'initialisation, encore faut-il le faire correctement : d'abord les constructeurs puis les variables membres, dans le même ordre que la définition.
    Et tu n'as pas l'impression d'avoir oublié d'appeler le constructeur de QObject ?

    connecté le signal de destruction de A à un slot qui tente d'accéder à la map par son getter
    Tu n'as pas peur que l'objet A soit détruit avant que tu n'es pu l'utiliser ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    A * a0 = qobject_cast<A*>(ai_item);   // CE CAST NE MARCHE PAS => NULL
    Cela doit venir du fait que tu n'as pas appelé le constructeur de QObject.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    QMap<QString, QPropertyAnimation*> m_propertiesAnimation;
    Il faut éviter les pointeurs nus. Utilise un QSharedPointeur ici.

    le static_cast marche mais la map est inaccessible !
    C'est que le cast ne fonctionne pas, même s'il en a l'air.

    Et s'il y en avait pas et qu'on ne devait pas en créer, quelle serait la solution ?
    Une solution est de créer une fonction "aboutToDelete" qui sera appelé juste avant le délete pour récupérer les infos et préparer à la destruction.

    Ce n'est pas un problème de conception. Juste peut être que tu n'y as pas encore été confronté !
    La classe A est un objet graphic qui gère une map de QPropertyAnimation des chacune de ses propriétés.
    Le but est que quand l'item graphique est détruit que l'animation manager le sache pour détruire la QPropertyAnimation qu'il gère ! Et la conception veut que chaque item graphique gère lui même ses QPropertyAnimation et que le manager ne fasse que de la lecture ...
    Il y a quand même un problème de conception. Tu le dis toi même : "chaque item gère lui même ses QPropertyAnimation". C'est donc tes items qui ont la responsabilité de la destruction des animations. Pourquoi le manager devrait aussi les gérer ?

Discussions similaires

  1. Réponses: 6
    Dernier message: 01/05/2006, 19h05
  2. Appel de fonction depuis une classe fille
    Par lhpp dans le forum Interfaces Graphiques en Java
    Réponses: 8
    Dernier message: 26/04/2006, 22h02
  3. Réponses: 8
    Dernier message: 22/03/2006, 18h24
  4. Héritage d'un événement pour une classe fille
    Par korntex5 dans le forum Langage
    Réponses: 4
    Dernier message: 11/01/2006, 16h48
  5. [debutant]appeller une fonction d'une classe fille et mere ?
    Par Battosaiii dans le forum Débuter
    Réponses: 1
    Dernier message: 12/11/2005, 12h56

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