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 :

Getter sur un pointeur de classe abstraite qui fait crash


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2015
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2015
    Messages : 23
    Par défaut Getter sur un pointeur de classe abstraite qui fait crash
    Bonjour,

    Je suis toujours sur mon projet étudiant de casse brique. Je suis confronté depuis quelques jours à un problème.
    Je souhaite diffuser un id dans mes formes pour pouvoir les reconnaître. J'ai quelques classes (raquette, balle, brique,...) qui héritent de forme et que je souhaite pouvoir identifier, pour connaître le contenu de mon pointeur forme * dans le code suivant (il peut aussi bien pointer sur un raquette que sur une balle, etc):

    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
    void balle::collision(const listeforme &liste)
    {
        float x,y;
        forme * pforme;
        for(int i = 0; i<4; i++)
        {
            x= scout[i].getx();
            y= scout[i].gety();
            pforme = liste.selection(x,y);//.selection(x,y);
            if((pforme!=this)&&(pforme!=NULL))
            {
                pforme->collision(this,i);
            }
     
        }
     //Fin de partie
        if(pforme->getIdforme()==1) //si c'est une raquette
        {
    //Traitement
        }
        ...
    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
    class forme
    {
        public:
            ...
            virtual int getIdforme();
     
        protected:
            int idforme;
            ...
        private:
    };
     
    .
    .
    .
     
    int forme::getIdforme()
    {
        return idforme;
    }
    Or le test suivant provoque le plantage de mon programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(pforme->getIdforme()==1)
    Le compilateur ne m'affiche aucune erreur, j'ai plus l'impression d'accéder à une partie de la mémoire qui ne m'appartient pas bizarrement.

    Si vous avez besoin de plus de détail, n'hésitez pas à me demander des précisions.

    Je vous remercie d'avance pour l'aide que vous pourrez m'apportez.

  2. #2
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut, et bienvenue (si je ne te l'ai pas encore souhaitée)
    Citation Envoyé par Exomus Voir le message
    Bonjour,

    Je suis toujours sur mon projet étudiant de casse brique. Je suis confronté depuis quelques jours à un problème.
    Je souhaite diffuser un id dans mes formes pour pouvoir les reconnaître. J'ai quelques classes (raquette, balle, brique,...) qui héritent de forme
    Houlala... Ca, c'est déjà mal barre...

    Car par définition, une forme ca va certes offrir un certain nombre de services mais... aucun qui ait le moindre rapport avec les services que l'on est en droit d'attendre de la part d'une balle, d'une raquette ou d'une brique ...
    et que je souhaite pouvoir identifier, pour connaître le contenu de mon pointeur forme * dans le code suivant (il peut aussi bien pointer sur un raquette que sur une balle, etc):
    Je vais être simple et direct : TU N'A PAS A CONNAITRE LE CONTENU DE QUOI QUE CE SOIT!!! Si tu places les données de tes classes dans l'accessibilité privée, c'est pour deux bonnes raisons:
    • La première, c'est que, en tant qu'utilisateur d'une classe (en gros : dés que tu as décidé "ok, j'ai créé ma classe, maintenant, je passe à ce qui l'utilise"), tu t'en fous royalement des données qui la composent (ou, du moins, tu devrais t'en foutre), car, tout ce qui t'intéresse (ou du moins, qui devrait t'intéresser), c'est sa capacité à répondre à certaines questions ou à réagir à certains ordres. (*)
    • La deuxième est plus simple encore : tu as mis les données dans l'accessibilité privée pour "garder le contrôle" des modifications qu'elles peuvent subir. Si, d'une manière ou d'une autre, tu permet à "n'importe qui" de voir "à quoi la donnée ressemble", ou pire encore, d'aller choisir lui-même la valeur qu'elle doit représenter (en prenant le risque que cette valeur soit erronée), tu avais sans doute plus simple de directement la placer dans l'accessibilité publique

    (*) C'est une erreur commune chez les débutants: beaucoup d'entre eux considèrent les classes comme des agrégats de données, alors qu'il faut les considérer comme des "fournisseurs de services". Autrement dit, la première question à se poser n'est pas "quelles données me permettront de représenter ce concept", mais bien "quels services vais-je attendre de sa part? à quelles questions devra-t-elle pouvoir répondre, quelles ordres voudrai-je pouvoir lui donner?"

    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
    void balle::collision(const listeforme &liste)
    {
        float x,y;
        forme * pforme;
        for(int i = 0; i<4; i++)
        {
            x= scout[i].getx();
            y= scout[i].gety();
            pforme = liste.selection(x,y);//.selection(x,y);
            if((pforme!=this)&&(pforme!=NULL))
            {
                pforme->collision(this,i);
            }
     
        }
     //Fin de partie
        if(pforme->getIdforme()==1) //si c'est une raquette
        {
    //Traitement
        }
        ...
    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
    class forme
    {
        public:
            ...
            virtual int getIdforme();
     
        protected:
            int idforme;
            ...
        private:
    };
     
    .
    .
    .
     
    int forme::getIdforme()
    {
        return idforme;
    }
    Or le test suivant provoque le plantage de mon programme :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    if(pforme->getIdforme()==1)
    Ca, c'est un coup classique : tu as libéré la mémoire dont l'adresse est représentée par un pointeur, mais tu ne l'as pas remis nullptr.

    Ceci dit, l'idéal serait sans doute de t'assurer que l'élément est supprimé de ta liste

    Et ce n'est, malheureusement, pas au niveau du code que tu présente, mais, cherches au niveau de delete que tu peux faire, l'erreur devrait trainer dans ce coin là (**)
    Le compilateur ne m'affiche aucune erreur, j'ai plus l'impression d'accéder à une partie de la mémoire qui ne m'appartient pas bizarrement.
    C'est surement parce que c'est ce qui se passe effectivement

    (**)C'est la raison pour laquelle nous insistons lourdement sur l'utilisation des pointeurs intelligents (std::unique_ptr serait parfaitement adapté dans ton cas). au lieu de faire delete liste.selection(x,y); tu ferais liste.selection(x,y).reset();.

    Et tu serais sur que, même si tu ne supprime pas l'élément de la liste, la prochaine fois que tu testera s'il est à null ou pas, il le sera bel et bien

    Sans compter tous les autres avantages liés aux "capsules RAII" dont les pointeurs intelligents sont les dignes représentants, bien sur
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 152
    Billets dans le blog
    4
    Par défaut
    Salut,

    si tu as besoin d'un id unique pour identifier une instance, this devrait faire l'affaire.
    Si tu espères selon cet id déduire le type réel de la classe, ce qui est ton cas puisque tu dis 1 = raquette : c'est certainement pas une bonne idée et tes classes sont à priori mal pensées, ou mal rangées.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  4. #4
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2015
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2015
    Messages : 23
    Par défaut
    Bonjour,

    Je comprends que c'est pas terrible comme solution. J'ai le besoin de connaître le contenu de pforme pour ma raquette, pour effectuer un simple traitement de fin de partie. En effet je souhaite traiter dans cette collision de balle, le cas où la balle n'est plus rattrapable ce qui met fin à la partie. Pour se faire j'ai besoin de récupérer la position de ma raquette au sein de collision. Il est apparu que passer un pointeur de raquette dans ma collision n'avait pas de sens, d'autant plus que par le passage de listeforme, je sais pertinemment que ma raquette est référencée dedans.
    Voici un schéma de ce que je souhaite réalisé :
    Pièce jointe 279207
    Or ce test de fin de partie dépend de la hauteur à laquelle est placée ma raquette (le traitement de la condition en dur n'est pas vraiment envisageable) et dépend de la position de ma raquette (si je suis dans la zone de réception de la raquette il ne peut y avoir fin de partie ce qui est logique, sinon je vérifie la condition de hauteur de ma balle)

    Ce que je comprends un petit peu moins, c'est d'accord mes attributs sont "protected", pour éviter que l'on accède aux attributs de ma classe que ce soit en lecture ou en écriture, mais pour le coup le Getter me paraissait une façon propre de retourner la valeur d'un attribut que j'autorise à être accessible en lecture qui est mon id. Ce dernier qui est commun à toutes mes formes, il était donc logique pour moi de diffuser au travers de l'héritage, cet attribut et la méthode getIdforme().
    Ce qui me parait dommage, c'est de passer ma liste de formes qui contient toutes les informations dont j'ai besoin, et de ne pas me servir de cet atout pour gérer ma fin de partie dans la collision de la balle (car pour moi fin de partie = collision avec la ligne de fin de partie).

    Je vous remercie d'avance pour vos réponses

  5. #5
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Exomus Voir le message
    Ce que je comprends un petit peu moins, c'est d'accord mes attributs sont "protected", pour éviter que l'on accède aux attributs de ma classe que ce soit en lecture ou en écriture,
    En théorie, les seules choses que tu devrais avoir dans les accessibilités publique et protégée sont... des fonctions membres. Les données, elles, devraient systématiquement être en accessibilité privée, quitte à fournir des fonctions (protégées) permettant aux classes dérivées de donner des ordres "privilégiées" (mais pas des accesseurs et des mutateurs, ca va de soi)

    Car le but d'une classe, c'est de faire respecter ses invariants par TOUT LE MONDE (y compris les classes dérivées), et, comme chaque classe est a priori seule à pouvoir les faire respecter sans se gourer... il faut bien limiter les risques au mieux
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  6. #6
    Membre averti
    Homme Profil pro
    Étudiant
    Inscrit en
    Février 2015
    Messages
    23
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 28
    Localisation : France, Seine et Marne (Île de France)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Février 2015
    Messages : 23
    Par défaut
    Citation Envoyé par koala01 Voir le message
    En théorie, les seules choses que tu devrais avoir dans les accessibilités publique et protégée sont... des fonctions membres. Les données, elles, devraient systématiquement être en accessibilité privée, quitte à fournir des fonctions (protégées) permettant aux classes dérivées de donner des ordres "privilégiées" (mais pas des accesseurs et des mutateurs, ca va de soi)

    Car le but d'une classe, c'est de faire respecter ses invariants par TOUT LE MONDE (y compris les classes dérivées), et, comme chaque classe est a priori seule à pouvoir les faire respecter sans se gourer... il faut bien limiter les risques au mieux

    En passant les attributs de ma classe en privé, mes classes n'hériteront plus de ces attributs non ? Donc par exemple, une brique qui hérite de rectangle n'aurait plus d'attributs p1, p2 qui définissent mon rectangle et donc la forme de ma brique ? Comment donc gérer par la suite la taille de ma brique, si je ne peux pas influencer mes attributs au travers des méthodes de ma brique ?

  7. #7
    Membre Expert
    Avatar de Pyramidev
    Homme Profil pro
    Tech Lead
    Inscrit en
    Avril 2016
    Messages
    1 513
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Tech Lead

    Informations forums :
    Inscription : Avril 2016
    Messages : 1 513
    Par défaut
    Citation Envoyé par Exomus Voir le message
    J'ai quelques classes (raquette, balle, brique,...) qui héritent de forme
    Contrairement à koala01, ça ne me choque pas. Par contre, ta fonction getIdforme() me choque.
    Si tu utilises de l'héritage pour gérer les collisions, il faudrait faire du double dispatch.
    Dans le cas présent, cela donnerait :
    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
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    class Balle;
    class Brique;
    class Raquette;
     
    class Forme
    {
    public:
    	void collisionAvec(Forme& forme)       {virtCollisionAvecForme(forme);}
    	void collisionAvec(Balle& balle)       {virtCollisionAvecBalle(balle);}
    	void collisionAvec(Brique& brique)     {virtCollisionAvecBrique(brique);}
    	void collisionAvec(Raquette& raquette) {virtCollisionAvecRaquette(raquette);}
    	// ...
    private:
    	virtual void virtCollisionAvecForme(Forme& forme)          = 0;
    	virtual void virtCollisionAvecBalle(Balle& balle)          = 0;
    	virtual void virtCollisionAvecBrique(Brique& brique)       = 0;
    	virtual void virtCollisionAvecRaquette(Raquette& raquette) = 0;
    	// ...
    };
     
    class Balle : public Forme
    {
    public:
    	// ...
    private:
    	void virtCollisionAvecForme(Forme& forme) override {forme.collisionAvec(*this);}
    	void virtCollisionAvecBalle(Balle& balle) override {
    		// Ne rien faire. (Les balles se traversent.)
    	}
    	void virtCollisionAvecBrique(Brique& brique) override {
    		// Rebondir.
    	}
    	void virtCollisionAvecRaquette(Raquette& raquette) override {
    		// Rebondir.
    	}
    	// ...
    };
     
    class Brique : public Forme
    {
    public:
    	// ...
    private:
    	void virtCollisionAvecForme(Forme& forme) override {forme.collisionAvec(*this);}
    	void virtCollisionAvecBalle(Balle& balle) override {
    		// Disparaître.
    	}
    	void virtCollisionAvecBrique(Brique& brique) override {
    		// Ne rien faire.
    	}
    	void virtCollisionAvecRaquette(Raquette& raquette) override {
    		// Ce n'est pas supposé pouvoir se produire.
    		// Possibilités : ne rien faire ou disparaître.
    	}
    	// ...
    };
     
    class Raquette : public Forme
    {
    public:
    	// ...
    private:
    	void virtCollisionAvecForme(Forme& forme) override {forme.collisionAvec(*this);}
    	void virtCollisionAvecBalle(Balle& balle) override {
    		// Ne rien faire.
    		// C'est Balle::virtCollisionAvecRaquette qui fait le boulot.
    	}
    	void virtCollisionAvecBrique(Brique& brique) override {
    		// Ce n'est pas supposé pouvoir se produire.
    		// Ne rien faire.
    	}
    	void virtCollisionAvecRaquette(Raquette& raquette) override {
    		// Cela pourrait se produire si on implémente le multi-joueurs.
    		// Ne rien faire.
    	}
    	// ...
    };

  8. #8
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 152
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 152
    Billets dans le blog
    4
    Par défaut
    Autant avoir raquette, balle et brique qui héritent de Forme pour l'affichage, pourquoi pas. Même si afficher un rectangle et un cercle n'ont pas grand rapport : l'un demande une position et une taille de côté, l'autre une position et un rayon.
    Autant pour le gameplay, elles n'ont rien à voir et ne devraient avoir aucun lien de parenté.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  9. #9
    Expert éminent
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 644
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 53
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Pyramidev Voir le message
    (1)Contrairement à koala01, ça ne me choque pas.
    Citation Envoyé par Bousk Voir le message
    (2)Autant avoir raquette, balle et brique qui héritent de Forme pour l'affichage, pourquoi pas. Même si afficher un rectangle et un cercle n'ont pas grand rapport : l'un demande une position et une taille de côté, l'autre une position et un rayon.
    (3)Autant pour le gameplay, elles n'ont rien à voir et ne devraient avoir aucun lien de parenté.
    (1) et (2) Et encore, ce qui importe au niveau de l'affichage, ce n'est pas tant de savoir que tu as affaire à une balle, une brique ou une raquette, que de savoir que tu doit afficher un rectangle ou un cercle de telle ou telle couleur à tel ou tel endroit.

    De plus, l'affichage entre très clairement dans la catégorie des éléments destinés à la vue, alors que les notions de balle, de raquette et de briques sont essentiellement des donnée métiers, c'est à dire destinées à faire partie du modèle.

    Et, rien que pour cela, il vaut déjà la peine de séparer clairement les deux notions, car la vue s'en contre fout de la "nature" de ce qu'elle doit afficher: on va lui demander d'afficher des rectangles et des cercles de différentes couleurs, et point barre.

    A contrario, les données métiers s'en contre foutent de savoir si ce sont des cercles ou des rectangles; et, encore plus, de savoir de quelle couleur sont ces formes. Tout ce qui les intéresse, c'est d'être en mesure de déterminer la position de l'élément au "tic" suivant et si ... l'espace occupé par l'une des donnée commence à "envahir" l'espace occupé par une autre.

    Alors, bien sur, tu vas sans doute me rétorquer que l'espace occupé par un des éléments dépend essentiellement de sa forme, mais c'est oublier un peu vite que la notion de formes vient avec une série d'informations et de services dont le modèle n'a que faire (comme le fait de connaitre la couleur, ou le fait de pouvoir l'afficher), et que tu peux éviter toute notion de forme si tu disposes du moyen de déterminer ... où s'arrête l'espace qu'elle occupe (par exemple, d'une formule permettant de calculer cette information).

    (3) Sur ce point là, je ne peux bien sur qu'être d'accord avec toi
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

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

Discussions similaires

  1. Réponses: 1
    Dernier message: 25/06/2011, 22h14
  2. Réponses: 2
    Dernier message: 30/12/2009, 20h44
  3. [Singleton] Class SQL qui fait planté le serveur
    Par Angelsafrania dans le forum ASP.NET
    Réponses: 6
    Dernier message: 25/06/2008, 13h22
  4. pb héritage sur classe abstraite et iterator
    Par black-falco dans le forum C++
    Réponses: 21
    Dernier message: 05/01/2008, 16h38
  5. polymorphisme, pointeurs et classes abstraites
    Par legend666 dans le forum C++
    Réponses: 10
    Dernier message: 02/11/2005, 16h44

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