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

Langage C++ Discussion :

Comment empêcher plusieurs instanciation d'une classe (à la compilation) ?


Sujet :

Langage C++

  1. #1
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut Comment empêcher plusieurs instanciation d'une classe (à la compilation) ?
    Salut,

    J'ai écris une classe Robot pour mon robot. Cette dernière est la classe principale de mon programme et hérite d'une autre classe. Il s'agit d'une classe abstraite permettant au programmeur de construire sa propre implémentation du robot. En tout logique, il ne devrait pas être possible de créer plusieurs instances de cette implémentation. De plus, j'ai prévu une méthode statique Robot::getContext() retournant une référence sur la classe Robot (un peu à la manière de QApplication::instance() en Qt).

    Quelle serait à votre avis la meilleure façon d'empêcher une instanciation multiple de la classe Robot en générant une erreur à la compilation (comportement qui se produit avec plusieurs QApplication je crois) ?

  2. #2
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    En rendant tous ses constructeurs privés?
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  3. #3
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    J'ai quand même besoin d'une instance au moins

  4. #4
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Que tu mets en static dans la classe elle-même (qui a donc accès à ses constructeurs).
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  5. #5
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Est-ce que tu peux illustrer par un exemple STP ?

  6. #6
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Actuellement, je gère la chose par le biais d'une exception, évidemment levée qu'à l'exécution :

    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
    class Robot
    {
        private:
            static Robot *context = nullptr;
     
            Robot(Robot const&) = delete;
            void operator =(Robot const&) = delete;
     
        protected:
            virtual void run() = 0;
     
        public:
            Robot(int argc, char *argv[])
            {
                 if (context != nullptr)
                 {
                     throw RobotException("already instanciated!");
                 }
     
                 context = this;
            }
     
            int start()
            {
                 run();
                 return 0;
            }
     
            static Robot &getContext()
            {
                 if (context == nullptr)
                 {
                      throw RobotException("not instanciated!");
                 }
     
                 return *context;
            }
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class MyRobot : public Robot
    {
        private:
            virtual void run()
            {
                 cout << "Hello World!" << endl;
            }
     
        public:
            MyRobot(int argc, char *argv[]) : Robot(argc, argv) {}
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    int main(int argc, char *argv[])
    {
         MyRobot robot(argc, argv);
         return robot.start();
    }

  7. #7
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    Renseigne toi sur le pattern "singleton".
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  8. #8
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Je connais très bien ce pattern. Je ne souhaite pas partager une instance entre plusieurs objets mais limiter le nombre d'instance et d'objet possible à une seule. En outre, je ne souhaite pas passer par une méthode supplémentaire. Enfin, j'aimerai détecter cette mauvaise utilisation de la classe le plus tôt possible, c-à-d à la compilation.

    J'ai pensé à la directive de précompilation #pragma. J'ai lu qu'il existe également une directive #error mais qui ne peut pas être utilisée dans une macro.

  9. #9
    Expert éminent sénior
    Avatar de Médinoc
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Septembre 2005
    Messages
    27 369
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 40
    Localisation : France

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Septembre 2005
    Messages : 27 369
    Points : 41 519
    Points
    41 519
    Par défaut
    [QUOTE De plus, j'ai prévu une méthode statique Robot::getContext() retournant une référence sur la classe Robot (un peu à la manière de QApplication::instance() en Qt).[/QUOTE]
    *Je ne souhaite pas partager une instance entre plusieurs objets
    Décide-toi

    Sérieusement, fais un singleton, ta méthode statique se chargera de créer, mémoriser et retourner l'objet.
    SVP, pas de questions techniques par MP. Surtout si je ne vous ai jamais parlé avant.

    "Aw, come on, who would be so stupid as to insert a cast to make an error go away without actually fixing the error?"
    Apparently everyone.
    -- Raymond Chen.
    Traduction obligatoire: "Oh, voyons, qui serait assez stupide pour mettre un cast pour faire disparaitre un message d'erreur sans vraiment corriger l'erreur?" - Apparemment, tout le monde. -- Raymond Chen.

  10. #10
    Expert éminent sénior

    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2007
    Messages
    5 189
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2007
    Messages : 5 189
    Points : 17 141
    Points
    17 141
    Par défaut
    En fait, si j'ai bien compris, ton problème est d'avoir une instance unique parmi toutes les classes dérivées de la classe de base?
    Ca sent le défaut de conception.

    Et si tu fais des threads, tu pourrais avoir un robot pour chacun, et donc plusieurs instance, non?

    Pour gérer un problème de nombre d'instances, il faut nécessairement passer par une information centralisée: un membre statique (ou une variable globale, qui peut être vue comme un membre statique du programme...)
    Mes principes de bases du codeur qui veut pouvoir dormir:
    • Une variable de moins est une source d'erreur en moins.
    • Un pointeur de moins est une montagne d'erreurs en moins.
    • Un copier-coller, ça doit se justifier... Deux, c'est un de trop.
    • jamais signifie "sauf si j'ai passé trois jours à prouver que je peux".
    • La plus sotte des questions est celle qu'on ne pose pas.
    Pour faire des graphes, essayez yEd.
    le ter nel est le titre porté par un de mes personnages de jeu de rôle

  11. #11
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Ma méthode getContext() permet d'éviter d'avoir à passer le pointeur this à chaque constructeur des classes instanciées dans run(). Robot étant une classe abstraite, si on par du principe que Robot possède une méthode Robot::getPosition() par exemple, l'utilisation de Robot::getContext() donne :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    myPosition = Robot::getContext().getPosition();
    C'est une pratique courante dans beaucoup d'API/SDK.

    En fait, si j'ai bien compris, ton problème est d'avoir une instance unique parmi toutes les classes dérivées de la classe de base?
    Ca sent le défaut de conception.

    Et si tu fais des threads, tu pourrais avoir un robot pour chacun, et donc plusieurs instance, non?
    En pratique, comme tu le vois dans mon main(), il n'y a qu'une seule classe dérivée de la classe Robot (l'intérêt d'en avoir plusieurs est très limité) et oui, cette classe dérivée ne devrait posséder qu'une seule instance car un robot ne peut exécuter qu'un seul programme à la fois.
    Il y a évidemment des threads pour réaliser différentes tâches bas niveau mais ils ne sont pas gérés par l'utilisateur. L'utilisateur est libre en revanche de créer ses propre classes et d'utiliser plusieurs threads avec ces dernières au sein de l'instance de la classe dérivée. Il peut également accéder aux méthode de Robot grâce à getContext(). Aujourd'hui j'empêche déjà l'instanciation multiple de Robot (CF mon code plus haut) mais à l'exécution seulement.

    En listant les sources de QCoreApplication je n'ai pas trouvé de mécanismes du préprocesseur ou autre qui empêche de créer plusieurs QApplication dans un même processus alors que tous les intervenant parlants du sujet expliquent que ça n'est pas possible/permis. L'idée serait la même dans mon cas.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    #include <QApplication>
     
    int main(int argc, char *argv[])
    {
         QApplication app(argc, argv);
         return app.exec();
    }

  12. #12
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Certes, mais tu n’as toujours pas expliqué pourquoi un brave singleton ne te convient pas. C’est juste fait pour ça en fait...

    Si je comprends bien, la classe explicite utilisée est choisie à la compilation. Donc tu peux faire un truc du genre :

    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
     
    // .h
    class AbstractRobot
    {
    private:
        AbstractRobot();
    public:
    AbstractRobot& instance();
    };
     
    // .h
    class RealRobot : public AbstractRobot
    {
      friend class AbstractRobot; // pour que AbstractRobot puisse l’instancier
    private:
      RealRobot();
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    // .cpp
    AbstractRobot& AbstractRobot::instance()
    {
    #if USE_ROBOT=REAL
       static RealRobot rob;
    #elseif USE_ROBOT= SIMUL
       static SimuRobot rob;
    #endif
       return rob;
    }
    Non ? (écrit à la rache, sans garantie d’erreur)

  13. #13
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Je ne veux pas de singleton parce que Qt le fait sans (et donc ça doit être possible) et parce que j'aimerai détecter cette mauvaise utilisation à la compilation (chose que je ne sais pas faire encore, contrairement au singleton).

    Ton exemple de singleton est faux car AbstractRobot doit connaître l'existance de RealRobot ou SimuRobot ce qui n'est pas le cas. L'utilisateur doit avoir le choix d'appeler sa classe MyRobot, Foo ou SimuRobot car c'est lui qui la programme. La classe abstraite Robot lui impose uniquement d'implémenter une méthode run(). C'est un pattern très répandu, typiquement ce qui se fait pour les Threads en Java. C'est aussi à l'utilisateur de gérer le démarrage de l'une ou l'autre des implémentations qu'il aura écrite.

  14. #14
    Membre actif Avatar de Rupella
    Inscrit en
    Février 2005
    Messages
    286
    Détails du profil
    Informations forums :
    Inscription : Février 2005
    Messages : 286
    Points : 257
    Points
    257
    Par défaut
    Qt fait comme ça, certes, mais les sources passent d'abord par leur moc.
    Il faut regarder les sources générées pour essayer de comprendre leur mécanisme qui leur permet d'empêcher l'utilisation multiple dès la compilation.

  15. #15
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par RPGamer Voir le message
    Je ne veux pas de singleton parce que Qt le fait sans (et donc ça doit être possible) et parce que j'aimerai détecter cette mauvaise utilisation à la compilation (chose que je ne sais pas faire encore, contrairement au singleton).
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    int main()
    {
        QApplication app;
        QApplication app2;
        return 0;
    }
    Compile parfaitement. Donc je ne vois pas ce que tu veux dire par « Qt le fait ».

    Ton exemple de singleton est faux car AbstractRobot doit connaître l'existance de RealRobot ou SimuRobot ce qui n'est pas le cas. L'utilisateur doit avoir le choix d'appeler sa classe MyRobot, Foo ou SimuRobot car c'est lui qui la programme. La classe abstraite Robot lui impose uniquement d'implémenter une méthode run(). C'est un pattern très répandu, typiquement ce qui se fait pour les Threads en Java. C'est aussi à l'utilisateur de gérer le démarrage de l'une ou l'autre des implémentations qu'il aura écrite.
    Tu veux un singleton et une fabrique. Ici j’ai regroupé les deux ensemble car c’est très nettement plus pratique et que ça me semblait correspondre à ton besoin (choix de l’implémentation à la compilation, garantie d’instanciation unique).

    Si tu as un besoin différent, initialise ton objet directement dans le main avec le type réel et passe le en paramètre (setContext). Pas besoin de plus compliqué.

  16. #16
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    Il est possible alors que les affirmations trouvées à ce sujet sur le net soient faussent ou simplement, et c'est probablement plus logique, que des appels à QApplication::exec() sur différentes instances soit interdit. Il y a forcément une limitation, à la compilation où à l'exécution, car le pointeur qApp ou la méthode QApplication::instance() ne peut pointer qu'une seule instance et dans ton code il y a ambiguïté. Il n'est pas impossible qu'il y aie un défaut de conception de ce côté mais c'est très peu probable.

    http://doc.qt.io/qt-5/qapplication.html#qApp

    Le problème principal avec ton exemple c'est que je ne peux pas modifier le code de Robot comme utilisateur (en tout cas à terme je ne peux pas car déjà compilé au sein d'une librairie) et que la méthode Robot::instance() constituerait une violation du mécanisme d'héritage ici.

    Si il n'existe pas de solution pour empêcher une compilation avec plusieurs instances (ou plusieurs appel à Robot::start()) dans le main(), je me contenterai de cette vérification à l'exécution.

  17. #17
    Membre émérite
    Avatar de white_tentacle
    Profil pro
    Inscrit en
    Novembre 2008
    Messages
    1 505
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2008
    Messages : 1 505
    Points : 2 799
    Points
    2 799
    Par défaut
    Citation Envoyé par RPGamer Voir le message
    Il est possible alors que les affirmations trouvées à ce sujet sur le net soient faussent ou simplement, et c'est probablement plus logique, que des appels à QApplication::exec() sur différentes instances soit interdit. Il y a forcément une limitation, à la compilation où à l'exécution, car le pointeur qApp ou la méthode QApplication::instance() ne peut pointer qu'une seule instance et dans ton code il y a ambiguïté. Il n'est pas impossible qu'il y aie un défaut de conception de ce côté mais c'est très peu probable.
    La vérification (si vérification il y a, je t’avoue que je n’en suis pas tout à fait sûr) est à l’exécution. Sinon, il est aussi possible de faire en sorte que quelque soit l’objet QApplication créé, il renvoie en fait toujours le même objet (mais de mémoire ce n’est pas le choix qui a été fait).

    Le problème que tu as, c’est qu’ici, tu as en plus un héritage.

    Le problème principal avec ton exemple c'est que je ne peux pas modifier le code de Robot comme utilisateur (en tout cas à terme je ne peux pas car déjà compilé au sein d'une librairie) et que la méthode Robot::instance() constituerait une violation du mécanisme d'héritage ici.
    Tu veux pouvoir vérifier à la compilation quelque chose qui n’existe pas encore à la compilation. Il n’y aura pas de miracle .

    je me contenterai de cette vérification à l'exécution.
    Une idée possible, est que ta bibliothèque utilise une fonction déclarée externe pour créer l’objet Robot. Quelque chose du genre :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    extern std::unique_ptr<AbstractRobot> createRealRobot();
     
    AbstractRobot& AbstractRobot::getContext() 
    {
        static std::unique_ptr<AbstractRobot>& context = createRealRobot();
    }
    À l’utilisateur de ta bibliothèque de fournir cette méthode. Le soucis, c’est que s’il ne le fait pas, ça va te donner des erreurs de link qui sont de manière générale assez pourries à diagnostiquer.

  18. #18
    Membre expérimenté

    Homme Profil pro
    Étudiant
    Inscrit en
    Novembre 2011
    Messages
    685
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Ain (Rhône Alpes)

    Informations professionnelles :
    Activité : Étudiant

    Informations forums :
    Inscription : Novembre 2011
    Messages : 685
    Points : 1 418
    Points
    1 418
    Par défaut
    Si tu ne veux pas utiliser de singleton, utilises une classe statique ou un namespace.

    Ton exemple de singleton est faux car AbstractRobot doit connaître l'existance de RealRobot ou SimuRobot ce qui n'est pas le cas. L'utilisateur doit avoir le choix d'appeler sa classe MyRobot, Foo ou SimuRobot car c'est lui qui la programme. La classe abstraite Robot lui impose uniquement d'implémenter une méthode run(). C'est un pattern très répandu, typiquement ce qui se fait pour les Threads en Java. C'est aussi à l'utilisateur de gérer le démarrage de l'une ou l'autre des implémentations qu'il aura écrite.
    ça mon ami tu as raison c'est une erreur de conception. Une classe mère n'a pas à connaitre ses enfants. Si Qt fait sans singleton, alors c'est qu'il fait une classe statique ou un namespace. Et, soit dit en passant, Qt n'est pas un modèle de conception


    Tu cherche à mettre dans ta biblio une classe Robot qui va se comporter comme les interfaces JAVA, c'est à dire qu'elle va forcer l'utilisateur à implémenter certaines méthodes. Il te faut donc définir, en C++, une classe abstraite pure que tes users seront obligés d'utiliser par héritage sur leurs propres spécialisations. Si ce que tu cherches à faire c'est l'équivalent du Runnable Java, Il faut juste que toutes les classes concrètes que tu vas fournir dans ton API fassent appel à ta classe abstraite pure. Ainsi l'utilisateur sera obligé d'en hériter je penses.
    Nullius in verba

  19. #19
    Membre émérite
    Avatar de prgasp77
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Juin 2004
    Messages
    1 306
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France, Eure (Haute Normandie)

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Juin 2004
    Messages : 1 306
    Points : 2 466
    Points
    2 466
    Par défaut
    Une classe Robot proposant un constructeur protected ? Le constructeur des classes directement héritées sera privée ; mais elles ne seront pas héritables à nouveau.

    Robot.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class Robot
    {
        static Robot* _context;
    protected:
        Robot() { _context = this; }
        virtual ~Robot() {}
     
        Robot(Robot const&) = delete;
        Robot& operator=(Robot const&) = delete;
    public: 
        static Robot& instance() { return *_context; } /** @todo Protect against SIGSEGV */
        virtual void run() = 0;
    };
    Robot.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Robot* Robot::_context = nullptr;

    RobotImpl.h
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    class RobotImpl : public Robot
    {
        static RobotImpl _instance;
    public:
        virtual void run() {}
    };
    RobotImpl.cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    RobotImpl RobotImpl::_instance;

    Usage
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    int main (int argc, char** argv)
    {
        Robot& r2d2 = Robot::instance();
    }
    -- Yankel Scialom

  20. #20
    Membre averti Avatar de RPGamer
    Homme Profil pro
    Ingénieur en systèmes embarqués
    Inscrit en
    Mars 2010
    Messages
    168
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 34
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ingénieur en systèmes embarqués

    Informations forums :
    Inscription : Mars 2010
    Messages : 168
    Points : 395
    Points
    395
    Par défaut
    La vérification (si vérification il y a, je t’avoue que je n’en suis pas tout à fait sûr) est à l’exécution. Sinon, il est aussi possible de faire en sorte que quelque soit l’objet QApplication créé, il renvoie en fait toujours le même objet (mais de mémoire ce n’est pas le choix qui a été fait).
    Si il n'y a aucun empêchement, alors il s'agit d'une erreur de conception car la valeur de qApp et celle de retour de QApplication::instance() seront indéterminées à l'exécution.

    Tu cherche à mettre dans ta biblio une classe Robot qui va se comporter comme les interfaces JAVA, c'est à dire qu'elle va forcer l'utilisateur à implémenter certaines méthodes. Il te faut donc définir, en C++, une classe abstraite pure que tes users seront obligés d'utiliser par héritage sur leurs propres spécialisations. Si ce que tu cherches à faire c'est l'équivalent du Runnable Java, Il faut juste que toutes les classes concrètes que tu vas fournir dans ton API fassent appel à ta classe abstraite pure. Ainsi l'utilisateur sera obligé d'en hériter je penses.
    Pas vraiment. Une interface ne possède que des signatures de méthodes en Java (pas d'implémentation et donc pas d'attributs) à la différence de la classe abstraite qui elle n'est tout simplement pas complétement implémentée (donc pas instanciable non plus). Le pattern que j'utilise est "fréquent" en Java car l'API native est plus riche en Java qu'en C++ mais il ne s'agit pas d'une particularité de ce langage donc je ne cherche pas à tout prix à reproduite le schéma de Runnable.

    Une classe Robot proposant un constructeur protected ? Le constructeur des classes directement héritées sera privée ; mais elles ne seront pas héritables à nouveau.
    C'est un exemple plus correct du singleton proposé par white_tentacle mais je n'ai pas besoin de partager une instance donc le singleton n'est pas vraiment ce que je voudrais faire. Il manque quand même l'appel au constructeur de Robot et le passage des arguments argc et argv à ton exemple.

    Merci pour vos propositions, je vais donc rester sur une vérification à l'exécution

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Réponses: 2
    Dernier message: 19/07/2015, 20h45
  2. Comment créer plusieur instance d'une class
    Par zyaya dans le forum C++Builder
    Réponses: 5
    Dernier message: 23/12/2010, 14h01
  3. Comment empêcher l'historisation d'une ou plusieurs commandes ?
    Par hisoft dans le forum Shell et commandes GNU
    Réponses: 13
    Dernier message: 27/04/2010, 15h11
  4. Réponses: 2
    Dernier message: 13/04/2010, 12h45
  5. Comment savoir avec quel JDK une classe est compilé
    Par menzlitsh dans le forum Langage
    Réponses: 1
    Dernier message: 11/05/2009, 17h21

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