La question Où devrais-je placer des fonctions qui ne sont pas liées à une classe a suscité un débat quant à savoir s'il est logique en C ++ de combiner des fonctions utilitaires dans une classe ou de simplement les faire exister en tant que fonctions libres dans un espace de noms.
Je viens d’un fond C # où cette dernière option n’existe pas et qui tend donc naturellement à utiliser des classes statiques dans le petit code C ++ que j’écris. La réponse la plus votée sur cette question ainsi que plusieurs commentaires indiquent toutefois que les fonctions libres doivent être préférées, suggérant même que les classes statiques étaient un anti-modèle. Pourquoi est-ce le cas en C ++? Au moins à la surface, les méthodes statiques sur une classe semblent impossible à distinguer des fonctions libres dans un espace de noms. Pourquoi donc la préférence pour ce dernier?
Les choses seraient-elles différentes si la collection de fonctions utilitaires nécessitait des données partagées, par exemple un cache que l'on pourrait stocker dans un champ statique privé?
la source
Réponses:
Je suppose que pour répondre à cela, nous devrions comparer les intentions des classes et des espaces de noms. Selon Wikipedia:
Classe
Espace de noms
Maintenant, qu'est-ce que vous essayez d'atteindre en plaçant les fonctions dans une classe (statique) ou un espace de noms? Je parierais que la définition d'un espace de noms décrit mieux votre intention - tout ce que vous voulez, c'est un conteneur pour vos fonctions. Vous n'avez besoin d'aucune des fonctionnalités décrites dans la définition de classe. Notez que les premiers mots de la définition de classe sont " Dans la programmation orientée objet ", pourtant il n'y a rien orienté objet dans une collection de fonctions.
Il y a probablement aussi des raisons techniques, mais en tant que personne venant de Java et essayant de comprendre le langage multi-paradigme qu'est C ++, la réponse la plus évidente est la suivante: parce que nous n'avons pas besoin de OO pour y parvenir.
la source
Je serais très prudent en appelant cela un anti-modèle. Les espaces de noms sont généralement préférés, mais comme il n’existe aucun modèle d’espace de noms et que ceux-ci ne peuvent pas être passés en tant que paramètres de modèle, il est assez courant d’utiliser des classes ne comportant que des membres statiques.
la source
À l'époque, j'avais besoin de suivre un cours de FORTRAN. Je connaissais d’autres langues impératives à ce moment-là, alors j’ai pensé que je pouvais faire du Fortran sans trop étudier. Lorsque j'ai rendu mes premiers devoirs, le professeur me les a retournés et m'a demandé de les refaire: il a dit que les programmes en Pascal écrits en syntaxe FORTRAN ne comptent pas comme des soumissions valables.
Un problème similaire est en jeu ici: utiliser des classes statiques pour héberger des fonctions utilitaires en C ++ est un idiome étranger à C ++.
Comme vous l'avez mentionné dans votre question, l'utilisation de classes statiques pour les fonctions utilitaires en C # est une nécessité: les fonctions autonomes ne sont tout simplement pas une option en C #. Le langage nécessaire pour développer un modèle permettant aux programmeurs de définir des fonctions indépendantes d'une autre manière, notamment dans les classes d'utilitaires statiques. C'était une astuce Java prise mot à mot: par exemple, java.lang.Math et System.Math de .NET sont presque isomorphes.
C ++, cependant, offre des espaces de noms, une installation différente pour atteindre le même objectif, et l’utilise activement dans l’implémentation de sa bibliothèque standard. L'ajout d'une couche supplémentaire de classes statiques est non seulement inutile, mais également quelque peu contre-intuitif pour les lecteurs sans arrière-plan C # ou Java. En un sens, vous introduisez une "traduction de prêt" dans la langue pour quelque chose qui peut être exprimé de manière native.
Lorsque vos fonctions doivent partager des données, la situation est différente. Comme vos fonctions ne sont plus sans lien , le modèle Singleton devient le moyen privilégié pour répondre à cette exigence.
la source
Peut-être devriez-vous vous demander pourquoi vous souhaitez une classe entièrement statique?
La seule raison pour laquelle je peux penser est que d'autres langages (Java et C #) qui sont vraiment «tout est une classe» en ont besoin. Ces langages ne peuvent pas du tout créer de fonctions de haut niveau. Ils ont donc inventé une astuce pour les conserver: il s'agissait de la fonction membre static. C'est un peu une solution de contournement, mais le C ++ n'en a pas besoin, vous pouvez créer directement de toutes nouvelles fonctions indépendantes.
Si vous avez besoin de fonctions qui fonctionnent sur un élément de données spécifique, il est judicieux de les regrouper dans une classe contenant les données, mais ces fonctions cessent d'être des fonctions et commencent à être membres de cette classe qui opère sur les données de la classe.
Si vous avez une fonction qui n’opère pas sur un type de données particulier (j’utilise le mot ici car les classes sont un moyen de définir de nouveaux types de données), c’est vraiment un anti-motif qui les place dans une classe, pour rien d’autre que fins sémantiques.
la source
En d'autres termes, avoir une classe au lieu d'un espace de noms n'a aucun avantage.
D'une part, cela vous évite de taper
static
tout le temps, bien qu'il s'agisse sans doute d'un avantage plutôt mineur.Le principal avantage est que c'est l'outil le moins puissant pour le travail. Les classes peuvent être utilisées pour créer des objets, elles peuvent être utilisées comme type de variables ou comme arguments de modèle. Aucune de ces fonctionnalités ne vous intéresse pour votre collection de fonctions. Il est donc préférable d'utiliser un outil qui ne possède pas ces fonctionnalités, afin que la classe ne puisse pas être utilisée de manière accidentelle.
Suite à cela, l'utilisation d'un espace de noms indique immédiatement à tous les utilisateurs de votre code qu'il s'agit d'un ensemble de fonctions et non d'un plan détaillé à partir duquel créer des objets.
la source
Une classe entièrement statique fera le travail, mais c'est comme conduire un camion semi-remorque de 53 pieds jusqu'à l'épicerie pour des frites et de la salsa quand une berline à quatre portes fera l'affaire (c'est-à-dire qu'elle est excessive). Les cours viennent avec une petite quantité de frais généraux supplémentaires et leur existence peut donner à quelqu'un l'impression qu'instancier un peut être une bonne idée. Les fonctions libres offertes par C ++ (et C, où toutes les fonctions sont gratuites) ne le font pas; ce ne sont que des fonctions et rien d'autre.
Pas vraiment. L'objectif initial de
static
C (et plus tard C ++) était de proposer un stockage persistant utilisable à n'importe quel niveau de portée:Vous pouvez placer l'étendue au niveau d'un fichier, ce qui la rend visible pour toutes les étendues plus étroites, mais pas en dehors du fichier:
Un membre de classe statique privé en C ++ a le même objectif mais est limité à la portée d'une classe. La technique utilisée dans l'
counter()
exemple ci-dessus fonctionne également dans les méthodes C ++ et est quelque chose que je vous conseillerais de faire si la variable n'a pas besoin d'être visible par toute la classe.la source
Si une fonction ne maintient aucun état et est réentrante, il semble inutile de la placer dans une classe (sauf si forcé par la langue). Si la fonction conserve un certain état (par exemple, elle ne peut être rendue thread-safe qu’à l’aide d’un mutex statique), les méthodes statiques sur une classe semblent alors appropriées.
la source
Une grande partie du discours sur le sujet fait ici sens, mais il y a quelque chose de très fondamental au sujet de C ++ qui fait
namespaces
etclass
es /struct
s très différent.Les classes statiques (les classes dont tous les membres sont statiques et où la classe ne sera jamais instanciée) sont elles-mêmes des objets. Ils ne sont pas simplement une
namespace
pour contenir des fonctions.La méta-programmation de modèles nous permet d'utiliser une classe statique en tant qu'objet à la compilation.
Considère ceci:
Pour l'utiliser, nous avons besoin de fonctions contenues dans une classe. Un espace de noms ne fonctionnera pas ici. Considérer:
Maintenant pour l'utiliser:
Tant en tant que nouveau allocateur expose une
allocate
etrelease
fonction compatible, le passage à une nouvelle allocateur est facile.Cela ne peut pas être réalisé avec des espaces de noms.
Avez-vous toujours besoin de fonctions pour faire partie d’une classe? Non.
L'utilisation d'une classe statique est-elle un anti-motif? Ça dépend du contexte.
Dans ce cas, ce que vous essayez d'atteindre sera probablement mieux servi par la programmation orientée objet.
la source
Comme John Carmack l'a dit:
"Parfois, l'implémentation élégante n'est qu'une fonction. Ce n'est pas une méthode. Ce n'est pas une classe. Ce n'est pas un framework. C'est juste une fonction."
Je pense que cela résume à peu près tout. Pourquoi voudriez-vous en faire une classe avec force si ce n'est clairement pas une classe? C ++ a le luxe que vous pouvez réellement utiliser des fonctions; en Java, tout est une méthode. Ensuite, vous avez besoin de nombreuses classes d’utilitaires.
la source