+ Répondre à la discussion
Affichage des résultats 1 à 7 sur 7
  1. #1
    Membre éprouvé
    Avatar de VivienD
    Homme Profil pro
    Ingénieur en génie électrique, électronique et informatique industrielle
    Inscrit en
    octobre 2009
    Messages
    262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Ingénieur en génie électrique, électronique et informatique industrielle
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : octobre 2009
    Messages : 262
    Points : 425
    Points
    425

    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 :
    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 :
    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 :
    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 :
    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 :
    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à.
    Timbré tatillon invétéré et fier de l'être!

    Digression du jour:
    SFINAE rocks!

  2. #2
    Membre Expert
    Avatar de imperio
    Homme Profil pro
    Étudiant
    Inscrit en
    mai 2010
    Messages
    616
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : mai 2010
    Messages : 616
    Points : 1 209
    Points
    1 209

    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
    Modérateur
    Avatar de koala01
    Inscrit en
    octobre 2004
    Messages
    9 783
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 783
    Points : 17 346
    Points
    17 346

    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 éprouvé
    Avatar de VivienD
    Homme Profil pro
    Ingénieur en génie électrique, électronique et informatique industrielle
    Inscrit en
    octobre 2009
    Messages
    262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Ingénieur en génie électrique, électronique et informatique industrielle
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : octobre 2009
    Messages : 262
    Points : 425
    Points
    425

    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 :
    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.
    Timbré tatillon invétéré et fier de l'être!

    Digression du jour:
    SFINAE rocks!

  5. #5
    Modérateur
    Avatar de koala01
    Inscrit en
    octobre 2004
    Messages
    9 783
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 783
    Points : 17 346
    Points
    17 346

    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 éprouvé
    Avatar de VivienD
    Homme Profil pro
    Ingénieur en génie électrique, électronique et informatique industrielle
    Inscrit en
    octobre 2009
    Messages
    262
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 24
    Localisation : Allemagne

    Informations professionnelles :
    Activité : Ingénieur en génie électrique, électronique et informatique industrielle
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : octobre 2009
    Messages : 262
    Points : 425
    Points
    425

    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.
    Timbré tatillon invétéré et fier de l'être!

    Digression du jour:
    SFINAE rocks!

  7. #7
    Modérateur
    Avatar de koala01
    Inscrit en
    octobre 2004
    Messages
    9 783
    Détails du profil
    Informations personnelles :
    Âge : 42

    Informations forums :
    Inscription : octobre 2004
    Messages : 9 783
    Points : 17 346
    Points
    17 346

    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

Liens sociaux

Règles de messages

  • Vous ne pouvez pas créer de nouvelles discussions
  • Vous ne pouvez pas envoyer des réponses
  • Vous ne pouvez pas envoyer des pièces jointes
  • Vous ne pouvez pas modifier vos messages
  •