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 :

Appel statique de fonction


Sujet :

C++

  1. #1
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 20
    Points : 17
    Points
    17
    Par défaut Appel statique de fonction
    Bonjour,

    Est-il possible en C++ de faire un appel de fonction (membre) statique, à l'instar des initialisations de variables statiques.
    Ex :
    Dans le header
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
     
    class A {
    public:
    static void f();
    };
    Dans le cpp
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    A::f()
    {
    //...
    }
     
    A::f();
    Le processeur me le refuse arguant qu'il s'agît d'une redéfinition de la fonction f.

    Merci d'avance.

  2. #2
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Bonjour,
    Pourtant ce code compile chez moi.
    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
     
    // Foo.h
    class Foo
    {
    public:
       static int bar();
    };
     
    // Foo.cpp
    #include "Foo.h"
     
    int Foo::bar()
    {
       return 3;
    }
     
    //main.cpp
    #include "Foo.h"
     
    int main()
    {
       int i = Foo::bar();
       return 0;
    }

  3. #3
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    Oui mais ce n'est pas ce que je voulais dire :
    De la même manière que l'initialisation d'une variable statique se fait en dehors de toute fonction, y a t il une manière de faire un appel de fonction statique en dehors de toute fonction ?

  4. #4
    Membre émérite

    Inscrit en
    Mai 2008
    Messages
    1 014
    Détails du profil
    Informations forums :
    Inscription : Mai 2008
    Messages : 1 014
    Points : 2 252
    Points
    2 252
    Par défaut
    Comment ça un appel hors de toute fonction ? Il prendrait place quand cet appel et qui serait l'appelant ?

  5. #5
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    Il prendrait sa place à un moment indéterminé, mais avant l'appel du main (comme l'initialisation des variables statiques).
    Non mais je pense que ce n'est pas possible, mais qu'une manière sale d'éviter le problème serait de faire un objet bidon qui se chargerait d'appeler la fonction dans le constructeur :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    class ObjetBidon {
    private:
      ObjetBidon()
      {
        A::f();
      }
      static ObjetBidon m_hiddenVar;
    };
     
    ObjetBidon ObjetBidon::m_hiddenVar();
    Avec toujours avec le risque que cet appel ne se fasse pas exactement au moment que l'on veuille.

  6. #6
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    Une solution à mon besoin peut être la suivante :

    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
     
    void f(); // La fonction f que je veux appeler une seule fois depuis la classe A. Elle peut aussi être membre de A ou d'une autre classe.
     
    class A
    {
     
    A* getInstance()
    {
    static A* instance = new A();
    return A;
    }
     
    private:
     
    A()
    {
      f();
    }
     
    };
    J'ai utilisé en même temps le design pattern singleton que j'avais aussi besoin d'utiliser pour l'application que je veux en faire. Du coup le constructeur de A n'est plus accessible de l'extérieur.

    Edit : l'aventure ne s'arrête finalement pas là... Cette "solution" nécessite tout de même qu'un appel à A::getInstance() soit effectué explicitement quelque part. Mais je commence à douter qu'il y ait vraiment une solution parfaite.

  7. #7
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Pour appeler une fonction membre, il faut un objet.
    Appeler une fonction membre sans objet est un non sens total.

    Quel est ton problème réel ? Que souhaites tu vraiment faire ?
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  8. #8
    Membre confirmé
    Inscrit en
    Juillet 2005
    Messages
    512
    Détails du profil
    Informations forums :
    Inscription : Juillet 2005
    Messages : 512
    Points : 641
    Points
    641
    Par défaut
    Citation Envoyé par Davidbrcz
    Pour appeler une fonction membre, il faut un objet.
    Appeler une fonction membre sans objet est un non sens total.
    Si elle est déclarée static ce qui semble être le cas dans son sujet.
    Elle peut être appelée sans qu'un objet soit crée.


    Pour thetux : Il n'est pas possible d'appeler une fonction en dehors d'une fonction.

  9. #9
    Rédacteur

    Avatar de Davidbrcz
    Homme Profil pro
    Ing Supaéro - Doctorant ONERA
    Inscrit en
    Juin 2006
    Messages
    2 307
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 32
    Localisation : Suisse

    Informations professionnelles :
    Activité : Ing Supaéro - Doctorant ONERA

    Informations forums :
    Inscription : Juin 2006
    Messages : 2 307
    Points : 4 732
    Points
    4 732
    Par défaut
    Citation Envoyé par Lucien63 Voir le message
    Si elle est déclarée static ce qui semble être le cas dans son sujet.
    Elle peut être appelée sans qu'un objet soit crée.
    Oui, ca je sais. J'ai oublié fonction membre non statique.
    "Never use brute force in fighting an exponential." (Andrei Alexandrescu)

    Mes articles dont Conseils divers sur le C++
    Une très bonne doc sur le C++ (en) Why linux is better (fr)

  10. #10
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    La fonction est bien statique. Donc oui je suis d'accord avec Lucien63.

    En fait je voulais faire une factory sans recenser les différentes versions d'un lecteur de fichiers dans la factory (pour pas la recompiler quand on rajoute une implémentation). Je voulais en fait que chaque classe s'auto-déclare dans la factory, pour que si par la suite on rajoute un autre type de lecteur de fichier, ni le code du main, ni celui de la factory ne soient modifiés.
    La seule manière que j'ai trouvée est de créer une fonction spécifique dans le main qui déclare toutes les variantes de l'objet à fabriquer dans la factory.

    Ex :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
     
    initFactory()
    {
    Factory::add("txt", fonctionStatique1);
    Factory::add("xml", fonctionStatique2);
    Factory::add("csv", fonctionStatique3);
    }
     
    int main(...)
    {
    ...
    initFactory();
    ...
    }
    Mais je ne pense pas que ce soit possible en fait.

    A moins qu'on ne fasse un objet statique dans la classe de chaque lecteur et que celui ci appelle la fonction statique de "recensement auprès de la factory" lors de sa construction ?

    Edit : Je suis tombé sur ce post : Implémentation du pattern Factory
    Comme quoi, c'est lorsque l'on ne cherche plus que l'on trouve par hasard ce que l'on cherche...
    La proposition de Médinoc rejoint donc ma dernière idée : il semble possible que les différents lecteurs s'auto-déclarent dans la factory.

    Reste qu'il faut faire attention en utilisant cela à l'allocation/désallocation de mémoire des variables statiques. La gestion de mémoire à laquelle je pense est de faire une variable statique (surtout pas un pointeur) dans la factory qui contient une liste de pointeurs des différents singletons des lecteurs. A la destruction, c'est le destructeur de la factory qui va se charger des delete de tous les fils. Ainsi on est sûr que chaque lecteur est détruit au moment adéquat, sans à avoir besoin d'appeler explicitement un quelconque destructeur à la fin du programme.

    Dites moi si jamais je me trompe.

    Edit : ça fonctionne en effet très bien, idem pour la mémoire qui se libère correctement, comme prévu.

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

    Informations professionnelles :
    Activité : aucun

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

    Ne serait-il pas préférable, plutôt que d'enregistrer une fonction, d'enregistrer une hiérarchie d'objets, dont le comportement est adapté à tes besoin réels

    Tu aurais donc une hiérarchie proche de
    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
    class Reader
    {
        public:
            virtual Reader(){}
            virtual type /*&*/ /*const */ read(/* arguments */) = 0;
            /* pour la fabrique */
            virtual Reader* clone() const = 0;
    };
    class XmlReader : public Reader
    {
        public:
            virtual type /*&*/ /*const */ read(/*  arguments */);
            virtual XmlReader* clone() const {return new XmlReader;}
    };
    class CsvReader : public Reader
    {
        public:
            virtual type /*&*/ /*const */ read(/*  arguments */);
            virtual CsvReader* clone() const {return new CsvReader;}
    };
    class TextReader : public Reader
    {
        public:
            virtual type /*&*/ /*const */ read(/*  arguments */);
            virtual TextReader* clone() const {return new TextReader;}
    };
    et ta factory proche de
    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
    class Factory
    {
        typedef std::map<std::string, Reader*> map;
        typedef map::const_iterator const_iterator;
        public:
            static Factory & instance()
            {
                static Factory f;
                return f;
            }
            /* permet l'enregistrement d'un nouveau reader */
            void registerReader(std::string const & s, Reader* r)
            {
                if(items_.find(s)==items_.end())
                    items_.insert(std::make_pair(s,r));
            }
            Reader* create(std::string const & s)
            {
                const_iterator it=items_.find(s);
                if(it==items_.end())
                    return NULL; /* pourrait lancer une exception */
                return (*it).second->clone();
            }
        private:
            /* on ne peut pas appeler directement le constructeur, vu que
             * la fabrique est un singleton 
             */
            Factory()
            {
                /* nous pouvons, pourquoi pas, déjà enregistrer certains readers*/
               registerReader("Xml", new XmlReader);
               registerReader("Csv", new CsvReader);
               registerReader("Text", new TextReader);
            }
            ~Factory()
            {
                 for(const_iterator it=items_.begin(); it!=items_.end();++it)
                     delete (*it).second;
            }
            /* un singleton n'est ni copiable ni assignable...
             * déclarons, sans les définir, le constructeur par copie et l'opérateur
             * d'affectation comme étant privés
             */
            Factory(Factory const&);
            Factory& operator(Factory );
            map items_;
    };
    Tu pourrais donc en arriver à une utilisation proche de
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    #include "OtherReader.h"
    #include "Factory.h"
    int main() /* ou n'importe quelle autre fonction  */
    {
         Factory::instance().registerReader("Other", new OtherReader);
    }
    NOTA: cela ne t'évitera de compiler qu'une partie seulement des fichiers
    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

  12. #12
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    Je n'avais apparemment pas tout dit sur les modifications que j'avais faites.
    J'ai en effet oublié l'idée de pointeur de fonction puisque je suis passé avec des singletons.

    Grossièrement j'ai le code suivant.
    Pour les lecteurs
    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
     
    class Reader
    {
        public:
            virtual type /*&*/ /*const */ read(/* arguments */) = 0;
    };
    class XmlReader : public Reader
    {
        public:
            virtual type /*&*/ /*const */ read(/*  arguments */);
        private:
            XmlReader()
            {
                 registerReader("XML", m_singleton);
            }
            static XmlReader* m_singleton;
     
    };
     
    XmlReader* XmlReader::m_singleton = new XmlReader();
    //... et ainsi de suite pour les autres lecteurs
    Pour la factory :
    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
     
    class Factory
    {
        typedef std::map<std::string, Reader*> map;
        typedef map::const_iterator const_iterator;
        public:
            static Factory & instance()
            {
                static Factory f;
                return f;
            }
            /* permet l'enregistrement d'un nouveau reader */
            void registerReader(std::string const & s, Reader* r)
            {
                if(items_.find(s)==items_.end())
                    items_.insert(std::make_pair(s,r));
            }
            Reader* create(std::string const & s)
            {
                const_iterator it=items_.find(s);
                if(it==items_.end())
                    return NULL; /* pourrait lancer une exception */
                return (*it).second;
            }
        private:
            Factory()
            {
                     // Rien à faire, mais le constructeur doit être private
            }
            ~Factory()
            {
                 for(map::iterator it=items_.begin(); it!=items_.end();++it) // Attention ici il faut pas un const_iterator ;)
                     delete (*it).second;
            }
            /* un singleton n'est ni copiable ni assignable...
             * déclarons, sans les définir, le constructeur par copie et l'opérateur
             * d'affectation comme étant privés
             */
            Factory(Factory const&);
            Factory& operator(Factory );
            map items_;
    };
    Mais je vais reprendre certaines de tes idées (je n'avais pas mis les constructeur et opérateur de copie en private par exemple).

    Cela permet de ne rien avoir à écrire dans le main : la variable statique du singleton de chaque lecteur appelle le constructeur private qui réalise alors son inscription auprès de la fabrique.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 614
    Points : 30 626
    Points
    30 626
    Par défaut
    En toute honnêteté, il n'y a, à mon sens, aucune raison pour que le sytème de lecture de fichier soit implémenté sous la forme d'un singleton...

    En effet, le pattern singleton te donne la certitude
    • qu'il n'existera qu'une et une seule instance de l'objet
    • que l'instance existera entre le moment de sa création et la fin du programme
    • que l'instance sera accessible depuis l'ensemble des points du programmes
    Un système de lecture de fichier n'a, a priori, aucun besoin de subir ce genre de restriction:

    • L'unicité d'instance peut poser problème dans le cadre d'une application multi threadée (deux threads nécessitant chacun une instance différente, pour gérer deux fichiers en même temps)
    • Un système de lecture de fichier n'a, bien souvent, aucun besoin d'exister durant toute la durée de l'exécution du programme
    • Si tu peux avoir besoin d'un système de lecture de fichiers à plusieurs endroits, le nombre de "point d'accès" vers ce type de ressources est, généralement, assez limité (un gestionnaire d'événement sur une IHM )
    De plus, comme tu sembles partir sur la base de l'utilisation d'un singleton afin de gérer les différents types de systèmes de lecture de fichiers, tu peux assez facilement envisager de simplement veiller à ce qu'il n'existe qu'une instance d'un type particulier dans la liste des systèmes de lecture et renvoyer, lors de l'appel d'une fonction du singleton, à renvoyer une référence (sans doute non constante) vers l'instance adéquate

    Enfin, tu trouvera un certain nombre de contributeurs sur ce forum qui sont pour le moins... mitigés quant à l'usage des singleton parce que le pattern s'apparente très fort à l'utilisation de ... variables globales, que l'on essaye de limiter autant que possible.

    J'ai donc réellement l'impression qu'il serait bon de revoir un peu ton analyse et ta conception afin d'intégrer cette remarque
    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

  14. #14
    Membre à l'essai
    Inscrit en
    Février 2008
    Messages
    20
    Détails du profil
    Informations forums :
    Inscription : Février 2008
    Messages : 20
    Points : 17
    Points
    17
    Par défaut
    Merci koala01 pour toutes ces remarques, très intéressantes et complètes.

    Je comprends ton point de vue, et je suis bien d'accord. Mais étant donné mes besoins (toujours une seule lecture dans toute l'application), je vais laisser ça comme ça. Bien que ça limite l'évolutivité si plus tard on a besoin de plusieurs objets ou que l'on travaille en multi-thread, l'avantage de cette solution est le fait qu'il n'y ai pas besoin de faire une fonction au démarrage qui déclare chacun des lecteurs auprès de la factory.

    Concernant des lecteurs qui sont en mémoire toute la durée du programme, les objets lecteurs ayant peu d'attributs, ils sont de petite taille et donc prendront logiquement que peu d'espace.

    Bref, j'ai bien conscience que c'est loin d'être la meilleure solution, mais je dois avancer, et ayant déjà consacré beaucoup de temps sur ceci, je préfère continuer ainsi. Si je disposais de tout le temps que je désirais, je retravaillerai dessus. Mais quoi qu'il en soit je garde présent à l'esprit ta solution, que j'appliquerai sans hésiter la prochaine fois que j'en aurai besoin.

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

Discussions similaires

  1. Fonctions appelées statiquement et dynamiquement
    Par ticroch dans le forum Langage
    Réponses: 2
    Dernier message: 28/09/2012, 22h42
  2. [Débutant] Appel d'une fonction non statique
    Par cool dans le forum Général Java
    Réponses: 3
    Dernier message: 21/08/2011, 19h20
  3. Réponses: 10
    Dernier message: 31/03/2010, 23h34
  4. [PHP 5.2] Appel dynamique de fonction statique
    Par gannher dans le forum Langage
    Réponses: 8
    Dernier message: 12/01/2010, 19h27
  5. appel xmlservice via fonction javascript
    Par pram dans le forum XMLRAD
    Réponses: 2
    Dernier message: 06/05/2003, 14h24

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