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 :

Attribut d'une classe du type d'une autre classe


Sujet :

C++

  1. #1
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 11
    Points : 5
    Points
    5
    Par défaut Attribut d'une classe du type d'une autre classe
    Bonjour, je suis en train de créer un petit jeu de shoot dans l'espace en C++.

    Lorsque je tente de définir dans mon header une classe dont l'attribut est de type d'une autre classe, j'ai le joli message d'erreur

    'MaClasse has not been declared'.
    'MaClasse does not name a type'

    Voici un exemple extrait de mon fichier Jeu.h :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    class Jeu {
        private:
        Vaisseau::Vaisseau joueur;
    };
    Je n'ai pas mis les autres méthodes et attributs.
    J'inclue bien le fichier Vaisseau.h dans mon Jeu.cpp.
    J'ai fait l'essai avec d'autres classes, rien à faire. Lorsque j'instancie la classe Vaisseau dans une méthode, pas de problème, mais pour la faire passer en attribut, j'ai ce message.

    J'ai procédé de cette manière là pour un autre projet et tout à fonctionné correctement, impossible de dire pourquoi là, ça bloque.

    Merci de m'apporter vos lumières

  2. #2
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    il faut prédéclarer Maclasse avant de décrarer jeu:
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  3. #3
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par méphistopheles Voir le message
    il faut prédéclarer Maclasse avant de décrarer jeu:
    Bonjour et merci de la rapidité de réponse,

    Ceci règle effectivement le problème du "'MaClasse has not been declared'." mais pas du "'MaClasse does not name a type".

  4. #4
    Membre éprouvé
    Avatar de méphistopheles
    Profil pro
    Inscrit en
    Janvier 2005
    Messages
    1 551
    Détails du profil
    Informations personnelles :
    Âge : 36
    Localisation : France

    Informations forums :
    Inscription : Janvier 2005
    Messages : 1 551
    Points : 1 220
    Points
    1 220
    Par défaut
    pourrais-tu me montrer la déclaration de Maclasse ainsi que l'endroit ou tu l'utilise, car comme ça, je ne vois pas trop... on dirais que maclasse n'a pas été déclaré... (ou alors que l'include est fait au mauvais endroit)
    Méphistophélès
    Si la solution ne résout pas votre problème, changez le problème...
    Cours et tutoriels C++ - FAQ C++ - Forum C++.

  5. #5
    Membre averti
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Points : 439
    Points
    439
    Par défaut
    Je ne suis pas sûr de comprendre ce que tu veux faire. Il me semble que si tu souhaites définir une donnée membre de la classe Jeu, tu dois utiliser une syntaxe du genre :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    nom_de_type nom_de_variable ;
    mais l'expression Vaisseau::Vaisseau joueur ne correspond pas à cela : elle désigne seulement un membre de la classe Vaisseau, et dire qu'un membre d'une classe B (ta classe Jeu) n'est rien d'autre que tel ou tel membre (public) d'une classe A (ta classe Vaisseau) n'est possible que si B est dérivé de A (??) or ta classe Jeu n'est pas dérivée de la classe Vaisseau...

  6. #6
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Pour préciser j'utilise la library graphique SFML.

    Vaisseau.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Vaisseau: public sf::Sprite {
    	private:
    	int vitesse;
    	sf::Image imgShipUp;
    	sf::Image imgShip;
    	sf::Image imgShipDown;
     
    	public:
    	Vaisseau();
    	void deplacer(sf::RenderWindow& App);
    };
    Jeu.h
    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
    class Vaisseau;
    class Jeu {
    	private:
            Vaisseau::Vaisseau joueur;
    	int vie;
    	int stage;
    	sf::Clock horloge;
    	sf::Image background[2];
    	sf::Sprite backgroundSprite[2];
    		
    	public:
    	Jeu();
    	void defilement(sf::RenderWindow& App);
    	void checkStage(sf::RenderWindow& App);
    };
    Début de Jeu.cpp
    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 <SFML/Graphics.hpp>
    //#include <stream.h>
    #include "Jeu.h"
    #include "Stage.h"
    #include "constantes.h"
    #include "Ennemi.h"
    #include "Kamikaze.h"
    #include "Vaisseau.h"
     
     
     
    Jeu::Jeu() {
    	background[0].LoadFromFile("bg1.jpg");
    	background[1].LoadFromFile("bg2.jpg");
    	backgroundSprite[0].SetImage(background[0]);
    	backgroundSprite[1].SetImage(background[1]);
    	backgroundSprite[1].SetX(LARGEURFENETRE);
    	stage=0;
    }

  7. #7
    Membre averti
    Profil pro
    professeur des universités à la retraite
    Inscrit en
    Août 2008
    Messages
    364
    Détails du profil
    Informations personnelles :
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : professeur des universités à la retraite

    Informations forums :
    Inscription : Août 2008
    Messages : 364
    Points : 439
    Points
    439
    Par défaut
    Nos messages se sont croisés... regarde plus haut.

    Vaisseau joueur n'est pas un membre de ta classe Vaisseau, l'expression Vaisseau::Vaisseau joueur qui veut dire 'le membre Vaisseau joueur de la classe Vaisseau' ne me semble donc pas avoir de sens.
    Peut-être voulais-tu écrire :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Vaisseau   Vaisseau_joueur;
    (qui signifie 'la variable Vaisseau_joueur, de type Vaisseau)

  8. #8
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Salut,

    La déclaration anticipée de classe ou de structure(ce que méphistopheles a (mal) désigné sous le terme de "prédéclarer Maclasse") permet au compilateur de savoir que la classe ou la structure déclarée anticipativement existe, mais ne permet pas au compilateur de connaitre le contenu de la classe ou de la structure.

    Cela implique qu'une déclaration anticipée ne sera utile au compilateur que tant qu'il n'a absolument pas besoin de connaitre le contenu de la classe ou de la structure déclarée anticipativement:

    Tant que l'on veut déclarer un pointeur ou une référence sur la classe ou la structure, cela suffira, mais, dés qu'il s'agit de déclarer une instance de la classe ou d'accéder à un membre (ou une fonction membre) de celle-ci, il faudra que le compilateur dispose de la définition complète du type concerné.

    Pour que le compilateur dispose de la définition complète du type concerné, il n'y a qu'une possibilité: inclure le fichier d'en-tête dans lequel le type en question est défini.

    Au final, la déclaration anticipée pourrait servir dans un code proche de
    fichier MyClass.hpp
    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
    class Vaisseau; //déclaration anticipée de la classe Vaisseau
    class MyClass
    {
        public:
            /* dans les deux cas ci-dessous, le compilateur doit juste savoir que
             * Vaisseau existe, la déclaration anticipée suffit ;)
             */
            void doSomething(Vaisseau&); 
            void doSomethingWithPtr(Vaisseau*);
        private:
            /* La taille d'un pointeur est connue (et correspond au nombre
             * de bits nécessaire pour représenter l'ensemble des adresses
             * mémoire accessibles par le système): la déclaration anticipée
             * suffit si on déclare un pointeur ;)
             */
            Vaisseau * levaisseau;
    };
    Par contre, les fonctions membres doSomething et doSomethingWithPtr vont - a priori - vouloir accéder au contenu (membres et ou fonctions membres) de Vaisseau...

    Le compilateur a donc besoin de connaitre la définition complète de Vaisseau, et il faudra donc inclure le fichier d'en-tête correspondant dans le fichier d'implémentation:
    fichier MyClass.cpp
    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
    /* il faut la définition de MyClass */
    #include "MyClass.hpp" 
    /* et celle de Vaisseau */
    #include "Vaisseau.hpp"
    /* si nous initialisions levaisseau à une instance créée dynamiquemement
     * de Vaisseau (new Vaisseau), le compilateur devrait connaitre le
     * constructeur de la classe Vaisseau (Vaisseau::Vaisseau() )
     */
    MyClass::MyClass():levaisseau(0)
    {
    }
    void MyClass::doSomething(Vaisseau& v)
    {
        //ici, il faut  que le compilateur connaisse Vaisseau::laFonction
        v.laFonction();
    }
    void MyClass::doSomethingWithPtr (Vaisseau* ptr)
    {
        //ici, il faut  que le compilateur connaisse Vaisseau::autreFonction
        v->autreFonction();
    }
    Si tu souhaite déclarer une instance de la classe, le compilateur doit connaitre le type complet, c'est à dire, disposer de la définition de la classe:
    fichier MyClass.hpp
    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
     
    /* Le meilleur moyen pour que le compilateur connaisse la totalité
     * de la classe Vaisseau, c'est d'inclure le fichier d'en-tête correspondant 
     */
    #include "Vaisseau.hpp"
    class MyClass
    {
        public:
            /* dans les deux cas ci-dessous, le compilateur doit juste savoir que
             * Vaisseau existe, la déclaration anticipée suffit ;)
             */
            void doSomething(Vaisseau&); 
            void doSomethingWithPtr(Vaisseau*);
        private:
            /* par contre, pour déclarer une instance de Vaisseau, la définition
             * de la classe est nécessaire
             */
           Vaisseau levaisseau;
    };
    Voici pour la règle générale

    Maintenant, lorsque tu écris un code proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Vaisseau::Vaisseau joueur;
    cela revient à demander au compilateur
    Citation Envoyé par toi au compilateur
    trouve un identifiant de type ou d'espace de noms nommé Vaisseau, et, dans ce type ou cet espace de noms, prend le type nommé Vaisseau
    Alors, de trois choses l'une:
    • Ou bien tu as effectivement défini la classe Vaisseau dans l'espace de noms... Vaisseau, et, honnêtement, il serait utile d'envisager de renommer l'un ou l'autre pour éviter de confondre
    • Ou bien, tu as définis un type imbriqué nommé Vaisseau dans ta classe... Vaisseau et, là aussi, il serait bon de renommer l'un ou l'autre pour éviter de confondre
    • Ou bien, tu n'as que la classe Vaisseau, et dans ce cas, tu dois déclarer ton instance de Vaisseau sous la forme de Vaisseau joueur;

    Dans tous les cas, le compilateur devra connaitre la définition complète du type Vaisseau, qu'il se trouve dans l'espace de noms Vaisseau, qu'il soit imbriqué dans un autre type Vaisseau ou qu'il s'agisse d'une erreur d'écriture
    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

  9. #9
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Effectivement, mon but était que l'attribut de la class Jeu soit une instance de la classe Joueur.
    Cependant inclure mon fichier Vaisseau.h dans mon fichier Jeu.h me génère des erreurs.

    "expected constructor, destructor, or type conversion before string constant" pointant sur include "Vaisseau.h" dans "Jeu.h".

  10. #10
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    Pourrais tu nous faire ici un copier / coller du fichier vaisseau.h

    Typiquement, j'aurais tendance à dire que tu as oublié le ";" apèrs l'accolade fermant la définition de l'une des classe qui s'y trouve, mais j'aimerais avoir confirmation
    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

  11. #11
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Pourrais tu nous faire ici un copier / coller du fichier vaisseau.h
    Bien sûr,

    Vaisseau.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Vaisseau: public sf::Sprite {
    	private:
    	int vitesse;
    	sf::Image imgShipUp;
    	sf::Image imgShip;
    	sf::Image imgShipDown;
     
    	public:
    	Vaisseau();
    	void deplacer(sf::RenderWindow& App);
    };
    Le simple fait d'ajouter la ligne "include "Vaisseau.h" " dans "Jeu.h" génère un grand nombre d'erreurs dans mon main.cpp et dans Vaisseau.h.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Jeu.h:9: error: expected constructor, destructor, or type conversion before string constant
    main.cpp:24: error: 'Jeu' has not been declared
    main.cpp:24: error: 'Jeu' was not declared in this scope
    main.cpp:24: error: expected `;' before 'partie'
    main.cpp:43: error: 'partie' was not declared in this scope
    main.cpp:44: error: no matching function for call to 'sf::RenderWindow::Draw(Vaisseau&)'

  12. #12
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 611
    Points
    30 611
    Par défaut
    (je m'attendais à ce que tu me fournisse le code complet de Vaisseau.h)

    As-tu bien inclus le fichier d'en-tête dans lequel est définie la class sf::Sprite dans Vaisseau.h (à vue d'oeil, je dirais un fichier "Sprite.h" de la bibliothèque SFML)
    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

  13. #13
    Futur Membre du Club
    Profil pro
    Inscrit en
    Mars 2009
    Messages
    11
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2009
    Messages : 11
    Points : 5
    Points
    5
    Par défaut
    Mon problème se situait dans l'ordre d'inclusion des fichier .h, en effet dans MaClasse.cpp il faut inclure MaClasse.h en dernier car si elle contient un attribut du type OtherClasse, OtherClasse.h doit être appelé avant.

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

Discussions similaires

  1. Réponses: 13
    Dernier message: 09/08/2012, 19h28
  2. [Modèle Relationnel] Faire une table par type ou une table des types ?
    Par jax54000 dans le forum Schéma
    Réponses: 12
    Dernier message: 18/11/2009, 12h43
  3. [Free Pascal] [2.2] Impossible d'assigner une variable de type T à une variable de type T
    Par Hibou57 dans le forum Free Pascal
    Réponses: 3
    Dernier message: 12/10/2007, 13h31
  4. Tester le type d'une variable de type "Variant"
    Par nono27200 dans le forum VB 6 et antérieur
    Réponses: 4
    Dernier message: 30/08/2007, 22h26
  5. Réponses: 2
    Dernier message: 10/04/2007, 13h39

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