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 :

Espaces de nommage, classes et prototypes


Sujet :

C++

  1. #1
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut Espaces de nommage, classes et prototypes
    Bonsoir,

    Je souhaitais apprendre à manipuler les espaces de nommage car c'est une notion que je n'avais guère abordée jusqu'ici. Pour ce faire, je me suis lancé dans le codage d'un analyseur de spectre fréquentiel via la méthode FFT.
    Tout d'abord j'ai créé un fichier en-tête fftsa.h pour mon espace de nommage. Voici le code qu'il contient:
    Code fftsa.h : 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
    #ifndef FFTSA_H
    #define FFTSA_H
     
    namespace FFTSA{
        //Constants
            //Light
            const double lowestMicrowaveFrequency = 300000000.0f; //300 MHz
            const double highestMicrowaveFrequency = 300000000000.0f; //300 GHz
            const double lowestIRLightFrequency = 300000000000.0f; //300 GHz
            const double highestIRLightFrequency = 405000000000000.0f; //405 THz
            const double lowestHumanlyVisibleLightFrequency = 405000000000000.0f; //405 THz (red)
            const double highestHumanlyVisibleLightFrequency = 790000000000000.0f; //790 THz (violet)
            const double lowestUVLightFrequency = 790000000000000.0f; //790 THz
            const double highestUVLightFrequency = 30000000000000000.0f; //30 PHz
            const double lowestXRayFrequency = 30000000000000000.0f; //30 PHz
            const double highestXRayFrequency = 30000000000000000000.0f; //30 EHz
            const double lowestGammaRayFrequency = 30000000000000000000.0f; //30 EHz
            //Sound
            const double lowestHumanlyAudibleSoundFrequency = 16.0f;
            const double highestHumanlyAudibleSoundFrequency = 20000.0f;
     
        //Classes
        class Engine;
    }
     
    #endif // FFTSA_H
    Comme vous avez pu le constater, cet espace contient le prototype d'une nouvelle classe, la classe Engine. J'ai choisi de la définir dans les fichiers fftsa_engine.h et fftsa_engine.cpp qui lui sont propres. Voici leur contenu:
    Code fftsa_engine.h : 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
    #ifndef FFTSA_ENGINE_H
    #define FFTSA_ENGINE_H
     
    #include <QObject>
    #include "fftsa.h"
     
    class FFTSA::Engine : public QObject
    {
        Q_OBJECT
     
        public:
            Engine();
            virtual ~Engine();
    };
     
    #endif // FFTSA_ENGINE_H
    Code fftsa_engine.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include "fftsa_engine.h"
     
    using namespace FFTSA;
     
    Engine::Engine() :
        QObject(0)
    {
     
    }
     
    Engine::~Engine()
    {
     
    }
    Rien de faramineux, je vous l'accorde. Ensuite j'ai décidé de tester ce peu de code avec le petit fichier source main.cpp suivant.
    Code main.cpp : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    #include <QApplication>
    #include "fftsa.h"
     
    int main(int argc, char* argv[])
    {
        QApplication app(argc, argv);
        FFTSA::Engine engine;
     
        return app.exec();
    }
    Et là, c'est le drame: ça ne compile pas. Outre le fait que j'obtiens un avertissement à cause de l'objet engine, le compilo me renvoie l'erreur suivante:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    aggregate 'FFTSA::Engine engine' has incomplete type and cannot be defined
    Malgré mes recherches sur Google, je ne parviens pas à comprendre le problème, ni à le résoudre; c'est pourquoi, je demande votre aide.

    Merci d'avance.

    Adishatz!

    PS: J'utilise la bibliothèque logicielle Qt 4.8.1, mais il me semble que ce problème ne vient pas de là.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  2. #2
    Membre émérite
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    Mai 2010
    Messages
    852
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2010
    Messages : 852
    Points : 2 298
    Points
    2 298
    Par défaut
    Il faut qu'à un moment ou un autre tu inclus l'entête de ta classe Engine (fftsa_engine.h) sinon le compilateur ne comprendra pas ce qu'est cette classe.

  3. #3
    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 612
    Points
    30 612
    Par défaut
    Salut,

    En fait, tu dois voir les espaces de nommages comme une sorte de "grosse boite" dans laquelle tu mets "tout ce qui va bien ensemble".

    Mais cela ne change pas grand chose aux règles de base concernant l'utilisation des différentes classes :

    Le fait de faire une déclaration anticipée d'une classe permet juste au compilateur de savoir qu'il existe un type portant ce nom, mais, dés qu'il doit utiliser un objet de ce type, il faut qu'il puisse déterminer la taille que cet objet utilise en mémoire, et, pour cela, il doit disposer de la définition complète

    Au final, même si tu as effectué une déclaration anticipée de ta classe dans le fichier fftsa.h, tu dois, aussi, inclure le fichier fftsa_engine.h dans main.cpp, histoire que le compilateur connaisse la classe quand il devra l'instancier
    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

  4. #4
    Membre émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    Citation Envoyé par imperio Voir le message
    Il faut qu'à un moment ou un autre tu inclus l'entête de ta classe Engine (fftsa_engine.h) sinon le compilateur ne comprendra pas ce qu'est cette classe.
    C'est vrai que je n'ai pas inclus ce fichier que ce soit dans fftsa.h ou dans main.cpp.

    Citation Envoyé par koala01 Voir le message
    [...]
    Le fait de faire une déclaration anticipée d'une classe permet juste au compilateur de savoir qu'il existe un type portant ce nom, mais, dés qu'il doit utiliser un objet de ce type, il faut qu'il puisse déterminer la taille que cet objet utilise en mémoire, et, pour cela, il doit disposer de la définition complète
    [...]
    Comme pour les fonctions, en gros.

    Citation Envoyé par koala01 Voir le message
    [...]
    Au final, même si tu as effectué une déclaration anticipée de ta classe dans le fichier fftsa.h, tu dois, aussi, inclure le fichier fftsa_engine.h dans main.cpp, histoire que le compilateur connaisse la classe quand il devra l'instancier
    Ça ne m'arrange pas trop, cette méthode. Je voudrais n'avoir qu'à inclure le fichier fftsa.h dans mon fichier main.cpp.

    Et si j'incluais mon fichier fftsa_engine.h dans mon fichier fftsa.h et que je réécrivais le fichier en-tête de ma class comme ci-dessous?
    Code fftsa_engine.h : 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
    #ifndef FFTSA_ENGINE_H
    #define FFTSA_ENGINE_H
     
    #include <QObject>
     
    namespace FFTSA{
     
        class Engine : public QObject
        {
            Q_OBJECT
     
            public:
                Engine();
                virtual ~Engine();
        };
     
    }
     
    #endif // FFTSA_ENGINE_H
    Après un petit test, ça a l'air de marcher mais j'ai des doutes.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  5. #5
    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 612
    Points
    30 612
    Par défaut
    Ce qui importe, c'est que la classe soit pleinement définie lorsque tu essayes d'en créer une instance.

    Le problème en incluant directement ton fichier fftsa_engine.h das fftsa.h, c'est que, si tu veux un jour ne disposer que des constantes que tu définis dans ce fichier, tu te retrouveras "malgré toi" avec une dépendance vis à vis de la classe aux conséquences parfois non voulues.

    Par exemple, tu te trouveras dans une situation dans laquelle un fichier cpp quelconque devra être recompilé parce que tu as modifié ta classe engine, alors que le fichier en question ne l'utilise absolument pas

    Une autre solution qui existe (mais bon, elle reste "moyen moyen"), c'est d'obscurcir completement ta classe engine, un peu à l'instar de ce qui est fait avec la structure FILE du C :

    Tu ne fais qu'une déclaration anticipée de enginge, et toutes les fonctions qui utilisent engine prennent un pointeur sur engine en argument (ou renvoient un pointeur sur engine comme valeur de retour).

    Evidemment, cela signifie que toutes les fonctions qui y font appel seront implémentées dans le fichier .cpp dans lequel engine est effectivement définie

    Enfin, et c'est peut etre la solution que je préféreais au final, il reste la solution d'avoir, en tout, trois fichiers d'en-tête :
    • Le premier serait fftsa_engine.h qui ne contient que la définition de engine (pour le cas où tu veux disposer de la classe "seule" et non des constantes)
    • le deuxième serait fftsa_constants.h et ne contiendrait que les constantes que tu définis actuellement dans fttsa.h, pour le cas où tu voudrais pouvoir ne disposer que des constantes seules (non de engine)
    • le troisième serait fttsa.h et ne contiendrait que l'inclusion de constants.h et celle de fftsa_engine.h, pour le cas où tu as besoin des deux

    Mais, ceci dit :
    • Qu'est ce qui te gène dans le fait de devoir inclure fftsa_engine.h pour pouvoir utiliser la classe
    • Y a-t-il une raison pour le faire hériter de QObject
    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 émérite
    Avatar de VivienD
    Homme Profil pro
    Développeur logiciel
    Inscrit en
    Octobre 2009
    Messages
    523
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 33
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Développeur logiciel
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Octobre 2009
    Messages : 523
    Points : 2 278
    Points
    2 278
    Par défaut
    Citation Envoyé par koala01 Voir le message
    [...]
    • Y a-t-il une raison pour le faire hériter de QObject
    Ma classe Engine utilisera le système de signaux et slots de Qt; pour ce faire, elle doit hériter de la classe QObject et contenir la macro Q_OBJECT.

    Citation Envoyé par koala01 Voir le message
    [...]
    [LIST][*]Qu'est ce qui te gène dans le fait de devoir inclure fftsa_engine.h pour pouvoir utiliser la classe
    À terme je voudrais créer une bibliothèque dynamique. Cette dernière contiendra un unique espace de nommage comprenant toutes les constantes, toutes les classes et toutes les fonctions nécessaires à mon analyseur spectral. Et, comme je n'aime pas avoir des fichiers fourre-tout bordélique qui font des milliers de lignes de long, je préfère tout compartimenter dans plein de petits fichiers bien ordonnés. Par ailleurs, je trouve que c'est plus simple de devoir écrire juste une ligne d'inclusion pour bénéficier d'un ensemble cohérent de fonctionnalités plutôt que d'en avoir à écrire toute une flopée aux proportions gargantuesques. Voilà pourquoi je souhaite avoir un fichier en-tête qui s'occupe de toutes les inclusions.

    Sur certains points, je peux être singulièrement pénible, perfectionniste et exigeant à la fois; je le sais et je le vis très bien.
    De retour, plus sportif mais toujours aussi moche.
    _____________
    Pro: Programmation en C/C++ (embarqué ou non)
    Loisir: Programmation en C++11/14/17 avec la STL ou Qt 5

  7. #7
    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 612
    Points
    30 612
    Par défaut
    Citation Envoyé par VivienD Voir le message
    Ma classe Engine utilisera le système de signaux et slots de Qt; pour ce faire, elle doit hériter de la classe QObject et contenir la macro Q_OBJECT.
    Oui, je sais...

    Mais, si c'est juste pour disposer d'un système de signaux et de slots, as tu déjà envisagé d'utiliser boost::signals, qui est non seulement plus près d'un C++ "propre", mais aussi sommes toutes beaucoup plus souple que le système de Qt.

    J'apprécie énormément Qt et il ne faut pas croire que je dénigre ce framework en aucune manière, mais je trouve peut etre dommage de se taper une dépendance envers lui uniquement pour profiter de ce qui est peut etre le moins abouti (en tout cas le moins bien étudié à la base) et qui a nécessité de passer par la création de moc

    Maintenant, tu restes de toutes manières entièrement libre de tes choix, bien sur
    [quote]
    À terme je voudrais créer une bibliothèque dynamique. Cette dernière contiendra un unique espace de nommage comprenant toutes les constantes, toutes les classes et toutes les fonctions nécessaires à mon analyseur spectral. [/QUOTESur ce point, tu as tout à fait raison.
    Et, comme je n'aime pas avoir des fichiers fourre-tout bordélique qui font des milliers de lignes de long, je préfère tout compartimenter dans plein de petits fichiers bien ordonnés. Par ailleurs, je trouve que c'est plus simple de devoir écrire juste une ligne d'inclusion pour bénéficier d'un ensemble cohérent de fonctionnalités plutôt que d'en avoir à écrire toute une flopée aux proportions gargantuesques.
    Je comprend ta motivation, mais je ne partage pas ta conclusion.

    L'idée qui sous tend à l'utilisation d'un fichier d'en-tête par classe est, justement, de permettre à l'utilisateur de n'inclure que ce dont il a besoin.

    Or, l'utilisateur de ta bibliothèque ne devra que très rarement recourir, dans un fichier d'implémentation, à l'ensemble des classes que proposera ta bibliothèque.

    Comme je l'ai dit, rien ne t'empêche de fournir un fichier d'en-tête qui inclus tous les autres, mais il me semble beaucoup plus cohérent, ne serait-ce que du point de vue de la compilation, de laisser à l'utilisateur le choix de ne pas inclure un fichier dont il n'a pas besoin.

    De plus, la première partie de ton raisonnement devrait, justement, t'inciter à avoir un grand nombre de fichiers d'en-tête pour éviter d'en avoir un seul "monolithique" en en créant, en gros, un par classe
    Sur certains points, je peux être singulièrement pénible, perfectionniste et exigeant à la fois; je le sais et je le vis très bien.
    Oh, sur ce point, tu ne tarderas pas à te rendre compte que je vaux mon pesant de cacahuètes
    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

Discussions similaires

  1. [Flash8] Espace de nommage dans un webservice
    Par memess dans le forum Flash
    Réponses: 1
    Dernier message: 01/03/2007, 09h19
  2. [c++] Mettre un callback dans un espace de nommage ou une class
    Par Spartan03 dans le forum GTK+ avec C & C++
    Réponses: 1
    Dernier message: 20/01/2007, 16h12
  3. Réponses: 2
    Dernier message: 05/09/2006, 10h08
  4. L'espace de nommage
    Par Shakan972 dans le forum C++
    Réponses: 1
    Dernier message: 02/11/2005, 15h49
  5. Réponses: 3
    Dernier message: 10/01/2005, 12h21

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