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 :

Fonction non membre non amie, ou fonction statique ?


Sujet :

C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut Fonction non membre non amie, ou fonction statique ?
    Hello,

    Soit une fonction membre méritant un découpage.
    Si les fonctions ainsi créées n'ont pas besoin de données membres de la classe, préférez-vous faire une fonction non membre non amie, ou une fonction membre statique ?

    Je sais que la première est généralement conseillée, mais j'apprécie la seconde forme (même si elle m'ouvre des droits supplémentaires dont je n'ai pas usage), notamment quand je dois faire quelques schémas UML.

  2. #2
    Rédacteur/Modérateur


    Homme Profil pro
    Network game programmer
    Inscrit en
    Juin 2010
    Messages
    7 147
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 38
    Localisation : Canada

    Informations professionnelles :
    Activité : Network game programmer

    Informations forums :
    Inscription : Juin 2010
    Messages : 7 147
    Billets dans le blog
    4
    Par défaut
    Soit la fonction a un sens à être externe à la classe, manipulation ultra haut niveau de données génériques, et je la mets non membre non amie afin qu'elle soit utilisable par d'autres.
    Soit la fonction sera utilisée uniquement dans le cadre de cette classe, manipulation de données internes ou structures internes, et static private, ou membre private parce que personne en dehors de la classe n'en a utilité.
    Pensez à consulter la FAQ ou les cours et tutoriels de la section C++.
    Un peu de programmation réseau ?
    Aucune aide via MP ne sera dispensée. Merci d'utiliser les forums prévus à cet effet.

  3. #3
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Bonjour,

    Cela va dépendre de ce que représente ta class\struct.
    La première forme est absolument pas envisageable de mon coté, c'est comme du gros C dégeux. La seule fois ou je me permets ça c'est d'avoir une fonction statique global à mon cpp.
    Invisible des autres unités elle permets de factoriser le fonctionnement interne d'un "Module"\"class"\"struct" et de le cacher à 100% à l'utilisateur si tu fait une librairie dynamique ou statique. Mais c'est tout!

    Pour une fonction utilisable par l'utilisateur, j'ai toujours choisi la seconde forme avec des fonctions statique de class car cela permet de les catégorisés! Et c'est important, ne serait-ce que pour la modularisation de ton code.
    Elle permets de savoir que ta fonction:static int32 Printf(const widechar* MsgFmt, ...); est une fonctionnalité de la console et donc de la noté comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct Console
    {
       static int32 Printf(const widechar* MsgFmt, ...);
    };
    Elle permets également de pouvoir faire de la spécification par plateforme!
    Exemple:
    La console commun, qui fourni une "interface" ou service commun à différent système:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct CommonConsole
    {
       static int32 Printf(const widechar* MsgFmt, ...);
    };
    La console Windows, qui fourni une spécialisation pour la plateforme Windows:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    struct WindowsConsole : public CommonConsole
    {
       static int32 Printf(const widechar* MsgFmt, ...);
    };
    La console de ton application est en fait un typedef de la console de plus bas niveau de hiérarchie:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    typedef WindowsConsole TheConsole;
    Ainsi tu utilises comme suit:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    TheConsole::Printf("Ok!");

    Lorsque tu ajoutes un nouveau système, tu n'as qu'a hérité de CommonConsole, comme par exemple une console Unix avec ces spécificités et ces propres types de base.
    Ainsi donc un cpp "WindowsConsole.cpp" tu n'as cas définir ta fonction pour Windows uniquement.

    L'utilisateur n'y vois que du feux, et sait que le printf est pour la console, tu pourrais très bien avoir un printf pour autre chose qu'une console après tout.

  4. #4
    Membre éprouvé
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    2 766
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Novembre 2004
    Messages : 2 766
    Par défaut
    Citation Envoyé par Astraya Voir le message
    La première forme est absolument pas envisageable de mon coté, c'est comme du gros C dégeux.
    Scott Meyers promeut pourtant cet usage, estimant que cela renforce l'encapsulation (et sa démonstration est convaincante).
    Je t'invite à relire son article (fin de la page 1).

    Citation Envoyé par Astraya Voir le message
    La seule fois ou je me permets ça c'est d'avoir une fonction statique global à mon cpp.
    Invisible des autres unités elle permets de factoriser le fonctionnement interne d'un "Module"\"class"\"struct" et de le cacher à 100% à l'utilisateur si tu fait une librairie dynamique ou statique. Mais c'est tout !
    En fait, ma question portait sur ce cas. Mais j'ai omis de le préciser...

    Citation Envoyé par Astraya Voir le message
    Pour une fonction utilisable par l'utilisateur, j'ai toujours choisi la seconde forme avec des fonctions statique de class car cela permet de les catégoriser !
    Pour la catégorisation, il y a la possibilité de rajouter un namespace.

    Toutefois, j'ai l'impression que ce sujet est de nature religieuse.
    Il y a un critère objectif (encapsulation), et d'autres plus subjectifs (lisibilité, documentation, raisonnement purement à base de classes pour ceux qui viennent de java ou C#.

  5. #5
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Scott Meyers promeut pourtant cet usage, estimant que cela renforce l'encapsulation (et sa démonstration est convaincante).
    Je t'invite à relire son article (fin de la page 1).
    Si la function global est dans un cpp je n'y vois pas d'inconvénient, je l'utilise souvent.
    Ce que je vois dans son exemple c'est que même sa fonction Widget* make( /* params */ ); est "Encapsuler" dans un namespace. Donc a partir de là je dirais que c'est plus une histoire de convention d'écriture vu que la fonction global est englober dans un namespace ou struct au final. Je pense que la décision final sera vraiment du cas par cas.
    Et comme il dit tout à la fin
    there is a weakness to this design when templates enter the picture.
    Pour la catégorisation, il y a la possibilité de rajouter un namespace.
    Le namespace ne te permettra pas d'overload de function si je dis vrai.

  6. #6
    Expert confirmé
    Avatar de Luc Hermitte
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2003
    Messages
    5 296
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Août 2003
    Messages : 5 296
    Par défaut
    Je préfère la fonction libre non amie.
    S'il y a besoin de cacher son existence, il suffit de la mettre dans un espace de noms anonymes.

    Il faut dire que je n'aime pas trop les fonctions statiques. Je trouve que cela a trop souvent un arrière goût de maladresse -- il y a des cas où c'est pertinent mais aussi beaucoup de cas où elles pourraient soit être libres, soit membres statiques d'une tierce classe (quand il y a des attributs statiques en plus).

    Le truc est que si tu n'as même pas besoin d'amitié dans le fonction libre, il me parait alors encore plus étrange de faire une fonction statique vu qu'il n'y a besoin d'aucun accès privilégié.

    Citation Envoyé par Astraya Voir le message
    Le namespace ne te permettra pas d'overload de function si je dis vrai.
    De surcharger oui, de masquer non.
    Blog|FAQ C++|FAQ fclc++|FAQ Comeau|FAQ C++lite|FAQ BS|Bons livres sur le C++
    Les MP ne sont pas une hotline. Je ne réponds à aucune question technique par le biais de ce média. Et de toutes façons, ma BAL sur dvpz est pleine...

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Salut,

    De manière générale, le respect de l'ISP devrait prévaloir dans ton choix sur ce thème. Du coup, par défaut, tu devrais choisir une fonction libre non amie.

    Cela n'a que des avantages, ne serait-ce que parce que tu peux alors placer la fonction dans un fichier d'en-tête clairement séparé
    Citation Envoyé par Astraya Voir le message
    Bonjour,

    Cela va dépendre de ce que représente ta class\struct.
    La première forme est absolument pas envisageable de mon coté, c'est comme du gros C dégeux. La seule fois ou je me permets ça c'est d'avoir une fonction statique global à mon cpp.
    Je ne vois pas pourquoi tu fais le parallèle entre des fonctions libres et du gros C dégeux!

    Nous ne sommes pas en java ou en C# avec les restrictions techniques que ces langages imposent: nous développons en C++, qui a le bon gout d'être véritablement un langage multi-paradigme.

    Bien au contraire, le fait de devoir déclarer la fonction principale comme étant une fonction statique est une aberration (j'ai eu envie de dire une abomination) conceptuelle en java. Bien sur, il y a de bonnes raisons techniques à cette nécessité et elles portent deux noms : machine virtuelle et garbage collector

    Mais, en C++, alors que l'on a la chance de pouvoir choisir le paradigme que l'on utilise de manière très modulaire, il serait aberrant de refuser de manière systématique l'utilisation de fonctions libres.

    Car il arrive souvent que tu veuille disposer d'un service particulier qui ne s'avère être utile que dans certaines circonstances particulière.

    Un exemple frappant de ce que je veux exprimer est la notion de matrice. A tord ou à raison, la première chose à laquelle on pense (en tant qu'informaticien) quand on parle de matrice, c'est à la représentation d'un tableau à deux dimensions. Et il se peut que, parfois, on en vienne à envisager la notion de matrice telle qu'elle nous est servie en mathématique. Avec, entre autres, le besoin d'en calculer le déterminant.

    On pourrait donc faire une fonction membre de notre classe Matrice qui permettrait de calculer le déterminant, mais cela aurait pour résultat que notre notion de matrice fournit "l'indispensable et le superflu", car on n'a pas forcément besoin de pouvoir calculer le déterminant d'une matrice lorsque la notion de matrice se limite à la notion de "représentation d'un tableau à deux dimensions".

    En créant une fonction libre pour calculer le déterminant, tu te mets en position, comme je l'ai dit, de déclarer cette fonction dans un autre fichier d'en-tête, et tu aurais dés lors Matrix.hpp qui fournit la notion "informaticienne" de matrice, et un fichier MatrixOperations.hpp (par exemple) qui exposeraient les opérations (de mathématique) matricielle "qui vont bien" pour un mathématicien
    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

  8. #8
    Membre Expert Avatar de Astraya
    Homme Profil pro
    Consommateur de café
    Inscrit en
    Mai 2007
    Messages
    1 048
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 39
    Localisation : France

    Informations professionnelles :
    Activité : Consommateur de café
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mai 2007
    Messages : 1 048
    Par défaut
    Citation Envoyé par koala01 Voir le message
    Salut,
    Mais, en C++, alors que l'on a la chance de pouvoir choisir le paradigme que l'on utilise de manière très modulaire, il serait aberrant de refuser de manière systématique l'utilisation de fonctions libres.
    Et les collisions de nom? Je le répète, dans un cpp no souci, dans un header vraiment pas...

    Citation Envoyé par koala01 Voir le message
    On pourrait donc faire une fonction membre de notre classe Matrice qui permettrait de calculer le déterminant, mais cela aurait pour résultat que notre notion de matrice fournit "l'indispensable et le superflu", car on n'a pas forcément besoin de pouvoir calculer le déterminant d'une matrice lorsque la notion de matrice se limite à la notion de "représentation d'un tableau à deux dimensions".

    En créant une fonction libre pour calculer le déterminant, tu te mets en position, comme je l'ai dit, de déclarer cette fonction dans un autre fichier d'en-tête, et tu aurais dés lors Matrix.hpp qui fournit la notion "informaticienne" de matrice, et un fichier MatrixOperations.hpp (par exemple) qui exposeraient les opérations (de mathématique) matricielle "qui vont bien" pour un mathématicien
    Le fait d'avoir 2 headers ajoute aussi une complexité non négligeable sur la gestion de version.... ( Git à le même soucis avec ces systèmes de modules qui peut apporter des bonnes régressions )

    Une matrice est un sens mathématique, un arrays est un sens "Autres".
    Prenons par exemple matlab qui différencie les deux https://fr.mathworks.com/help/matlab/learn_matlab/matrices-and-arrays.html?requestedDomain=www.mathworks.com

    Une matrix peut aussi être une spécialisation (Dans le sens héritages) avec des fonctions supplémentaires. Un array est une classe template<X,Y> Array et une matrix est template<> Matrix : public Array<4,4>De plus, le fait d'avoir la class Mvatrix avec c'est fonctions membres permets d'obtenir une "Documentation" sur ce qui est possible ou pas.


    Mais encore une fois, j'ai plus l'impression que c'est une question religieuse que d'efficacité. Le multiparadigm permets beaucoup de chose comme tu le dis koala.

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

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 644
    Par défaut
    Citation Envoyé par Astraya Voir le message
    Et les collisions de nom? Je le répète, dans un cpp no souci, dans un header vraiment pas...
    Et les espaces de noms, c'est fait pour les chiens

    Si tu as des fonctionnalités qui sont corrélées d'une manière ou d'une autre, tu les places dans un espace de noms identique, et basta
    Le fait d'avoir 2 headers ajoute aussi une complexité non négligeable sur la gestion de version.... ( Git à le même soucis avec ces systèmes de modules qui peut apporter des bonnes régressions )
    La gestion de versions concurrente a toujours été un problème. Mais ce n'est pas là que le bât blesse...

    Là où le bât blesse, en terme de régression, c'est en termes de tests unitaire; pour que l'on puisse garantir que, quelle que soit la fonctionnalité envisagée, elle réagira effectivement de la manière qui est attendue.

    Et de mon point de vue, il est toujours plus facile de s'y retrouver dans dix fichiers de 100 lignes que dans un seul fichier de 1000
    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

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

Discussions similaires

  1. Réponses: 10
    Dernier message: 31/03/2010, 23h34
  2. Fonction membre non-reconnue par le compilateur.
    Par markfish55 dans le forum C++
    Réponses: 2
    Dernier message: 06/06/2008, 04h36
  3. Boost thread avec fonction membre non statique.
    Par Klaim dans le forum Boost
    Réponses: 2
    Dernier message: 11/08/2007, 02h58
  4. Réponses: 1
    Dernier message: 24/11/2006, 16h15
  5. Réponses: 3
    Dernier message: 22/11/2006, 21h10

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