Que signifie le préfixe de variable `m_`?

155

Je vois souvent le m_préfixe utilisé pour les variables ( m_World, m_Sprites...) dans des tutoriels, des exemples et autres codes principalement liés au développement du jeu.

Pourquoi les gens ajoutent-ils un préfixe m_aux variables?

kravémir
la source
18
Avant de suivre sans réfléchir la notation hongroise, veuillez vérifier ce qu'est vraiment la notation hongroise. Parce que nommer un iCounter int est tout simplement inutile. Mais nommer un int xAnnotationPos et yAnnotationPos est raisonnable. Utilisez la version sémantique.
AkselK
Parfois, les modules importés préfixent les fonctions et les variables afin que vous soyez moins susceptible de les écraser avec votre propre code. C'est une manière de «réserver» des noms pour un usage spécifique.
earthmeLon
3
Alors que la notation «hongroise» est souvent vicieusement ridiculisée, la saveur particulière de celle-ci qui dénote une portée variable présente de réels avantages. En plus d'identifier la portée de la variable, cela évite les collisions de noms, comme lorsqu'un local, un parm et un membre ont tous la même intention, et donc le même nom «sémantique». Cela peut rendre la maintenance de bases de code volumineuses plus simple et moins sujette aux erreurs.
Hot Licks
8
Il existe des arguments pour et contre toute norme de codage, mais la question demande clairement à quoi cela sert m_, mais la moitié des réponses ici sont un commentaire sur les raisons pour lesquelles tout le monde pense que son favori actuel est le meilleur.
cz

Réponses:

108

Il s'agit d'une pratique de programmation typique pour définir des variables qui sont des variables membres. Ainsi, lorsque vous les utilisez plus tard, vous n'avez pas besoin de voir où ils sont définis pour connaître leur portée. C'est également génial si vous connaissez déjà la portée et que vous utilisez quelque chose comme intelliSense , vous pouvez commencer par m_et une liste de toutes vos variables membres s'affiche. Une partie de la notation hongroise, voir la partie sur la portée dans les exemples ici .

MichaelMaison
la source
51
Le pire argument pour une convention de dénomination, vous pouvez simplement appuyer sur ctrl + espace pour intellisense.
orlp
11
@nightcracker eventhough que je n'aime pas le préfixe, il veut dire que lorsque vous tapez m_ puis "CTRL + ESPACE" (sauf si c'est automatique) vous obtenez une liste contenant uniquement vos membres. Ce n'est pas exactement une bonne raison mais c'est un plus.
Sidar
13
Il convient de mentionner qu'il existe de nombreuses autres façons plus ou moins standard de faire la même chose; "m_variable", "m_Variable", "mVariable", "_variable", "_Variable" ... quel chemin est "meilleur" ou "juste" (ou s'il faut le faire du tout) est un argument aussi controversé et stérile que " espaces vs tabulations ». :)
Trevor Powell
49
Je préfère simplement utiliser "this->" - un peu rend "m_" redondant et c'est encore mieux car il est appliqué par le compilateur (en théorie, vous pouvez afficher "m_" sur n'importe quel type de variable; ne peut pas faire cela avec "this-> "). Une partie de moi souhaite que C ++ soit simplement normalisé en rendant "this->" obligatoire. Mais cela va plus dans le monde de la discussion que d'être une réponse.
3
@LaurentCouvidou, vous ne pouvez pas vraiment imposer aux développeurs de créer des variables membres préfixées par l'un m_ou l'autre.
SomeWritesRéservé
94

Dans Clean Code: A Handbook of Agile Software Craftsmanship, il y a une recommandation explicite contre l'utilisation de ce préfixe:

Vous n'avez pas non plus besoin de préfixer les variables membres avec m_. Vos classes et fonctions doivent être suffisamment petites pour que vous n'en ayez pas besoin.

Il existe également un exemple (code C #) de ceci:

Mauvaise pratique:

public class Part
{
    private String m_dsc; // The textual description

    void SetName(string name)
    {
        m_dsc = name;
    }
}

Bonnes pratiques:

public class Part
{
    private String description;

    void SetDescription(string description)
    {
        this.description = description;
    }
}

Nous comptons avec des constructions de langage pour désigner les variables membres dans le cas d'ambiguïté explicitement ( c. -à , descriptionmembre et descriptionparamètres): this.

InfZero
la source
6
Le libellé pourrait être "il y a une recommandation explicite CONTRE l'utilisation de ce préfixe:"
Xofo
Je suis si heureux que quelqu'un l'ait écrit
dmitreyg
Une autre raison est que dans java getter / setter est supposé être getName / setName, donc getM_name est mauvais et vous devez les gérer un par un.
Leon
Merci d'avoir écrit ceci. Je voulais juste souligner que le livre que vous avez cité est sorti depuis août 2008 - et je trouve toujours cette mauvaise pratique dans le nouveau code aujourd'hui (2019).
alexlomba87
20

C'est une pratique courante en C ++. En effet, en C ++, vous ne pouvez pas avoir le même nom pour la fonction membre et la variable membre, et les fonctions getter sont souvent nommées sans le préfixe "get".

class Person
{
   public:
      std::string name() const;

   private:
      std::string name; // This would lead to a compilation error.
      std::string m_name; // OK.
};

main.cpp:9:19: error: duplicate member 'name'
      std::string name;
                  ^
main.cpp:6:19: note: previous declaration is here
      std::string name() const;
                  ^
1 error generated.

http://coliru.stacked-crooked.com/a/f38e7dbb047687ad

"m_" indique le "membre". Le préfixe "_" est également courant.

Vous ne devriez pas l'utiliser dans les langages de programmation qui résolvent ce problème en utilisant différentes conventions / grammaires.

doc
la source
11

Le m_préfixe est souvent utilisé pour les variables membres - je pense que son principal avantage est qu'il aide à créer une distinction claire entre une propriété publique et la variable de membre privé qui la soutient:

int m_something

public int Something => this.m_something; 

Il peut être utile d'avoir une convention de dénomination cohérente pour les variables de sauvegarde, et le m_préfixe est une façon de le faire - une méthode qui fonctionne dans les langages insensibles à la casse.

Son utilité dépend des langues et des outils que vous utilisez. Les IDE modernes dotés d'outils de refactorisation puissants et d'intellisense ont moins besoin de conventions comme celle-ci, et ce n'est certainement pas la seule façon de le faire, mais cela vaut la peine d'être conscient de la pratique dans tous les cas.

Keith
la source
5
Si vous devez écrire this.dans votre langue, alors m_c'est vraiment inutile.
Ruslan
@Ruslan le m_est de le distinguer de la propriété qu'il soutient - donc this.Somethingpour la propriété vs this.m_somethingpour le membre de soutien. Ce n'est pas une convention que je préfère moi-même, mais je l'ai surtout vue utilisée dans des langages insensibles à la casse (comme VB).
Keith
1
Pourquoi pas, this.Somethingpour la propriété et this.somethingpour le support? Ou this._somethingpour le support? this.m_somethingest redondant. Je l'utilise _somethingpour ne pas le taper accidentellement quand je vais taper Something, rien à voir avec l'appartenance ou pas
AustinWBryan
@AustinWBryan voir mon commentaire précédent sur les langages insensibles à la casse. Ouais, un _préfixe seul ferait l'affaire, mais m_c'est la convention. Ce n'est pas celui que j'utiliserais personnellement, mais si vous le voyez dans le code, c'était l'intention de l'auteur.
Keith
7

Comme indiqué dans les autres réponses, le m_préfixe est utilisé pour indiquer qu'une variable est un membre de la classe. Ceci est différent de la notation hongroise car elle n'indique pas le type de la variable mais son contexte.

J'utilise m_en C ++ mais pas dans d'autres langages où «this» ou «self» est obligatoire. Je n'aime pas voir «this->» utilisé avec C ++ car il encombre le code.

Une autre réponse dit m_dscest «mauvaise pratique» et «description»; est une "bonne pratique" mais c'est un hareng rouge parce que le problème là-bas est l'abréviation.

Une autre réponse dit que la saisie fait thisapparaître IntelliSense, mais tout bon IDE aura un raccourci clavier pour afficher IntelliSense pour les membres actuels de la classe.

Quentin 2
la source
"mais c'est un hareng rouge" - Bon point. Une comparaison équitable serait m_descriptionvs description.
Bataille le
3

Comme indiqué dans de nombreuses autres réponses, m_ est un préfixe qui désigne les variables membres. Il est / était couramment utilisé dans le monde C ++ et propagé à d'autres langages, y compris Java.

Dans un IDE moderne, il est complètement redondant car la coloration syntaxique montre clairement quelles variables sont locales et lesquelles sont membres . Cependant, au moment où la coloration syntaxique est apparue à la fin des années 90, la convention existait depuis de nombreuses années et était fermement établie (du moins dans le monde C ++).

Je ne sais pas à quels tutoriels vous faites référence, mais je suppose qu'ils utilisent la convention en raison de l'un des deux facteurs suivants:

  • Ce sont des tutoriels C ++, écrits par des personnes habituées à la convention m_, et / ou ...
  • Ils écrivent du code en texte brut (monospace), sans coloration syntaxique, la convention m_ est donc utile pour rendre les exemples plus clairs.
sergut
la source
Un exemple pourrait être celui-ci: wiki.qt.io/How_to_Use_QSettings Puisque Qt Creator utilise la mise en évidence, la première estimation peut apparaître. Un peu différente pourrait être une autre convention utilisant _object () pour les objets privés d'une classe et p_variable s'il s'agit d'un pointeur car les deux ne sont pas surlignés comme je le sais et semblent avoir du sens pour moi de l'utiliser.
Ivanovic le
3

Lockheed Martin utilise un schéma de nommage à 3 préfixes avec lequel il était merveilleux de travailler, en particulier lors de la lecture du code des autres.

   Scope          Reference Type(*Case-by-Case)   Type

   member   m     pointer p                       integer n
   argument a     reference r                     short   n
   local    l                                     float   f
                                                  double  f
                                                  boolean b

Alors...

int A::methodCall(float af_Argument1, int* apn_Arg2)
{
    lpn_Temp = apn_Arg2;
    mpf_Oops = lpn_Temp;  // Here I can see I made a mistake, I should not assign an int* to a float*
}

Prenez-le pour ce qu'il vaut.

jiveturkey
la source
Impressionnant. Merci pour "l'exemple". Là où cela est vraiment utile, c'est lorsque vous éditez 200 000 lignes de code.
jiveturkey
1
Nul besoin d'être sur la défensive. J'essaie honnêtement de vous aider en vous montrant qu'il y a une erreur dans votre réponse. Permettez-moi d'être plus clair, alors: peu importe si vous avez 5 ou 200000 lignes de code: le compilateur ne vous laissera pas faire une affectation avec des types de pointeurs incompatibles. Le point soulevé dans le commentaire est donc sans objet.
Cássio Renan le
Je ne voulais pas se montrer défensif. Désolé.
jiveturkey le
C'est une variation de la notation hongroise, qui n'a pas de sens dans les langues modernes ...
doc
2

Pour compléter les réponses actuelles et comme la question n'est pas spécifique au langage, certains projets C utilisent le préfixe m_pour définir des variables globales spécifiques à un fichier - et g_pour les variables globales dont la portée est plus grande que le fichier dans lequel elles sont définies.
Dans ce cas, les variables globales définies avec le préfixe m_ doivent être définies comme static.

Voir la convention de codage EDK2 (une implémentation UEFI Open-Source) pour un exemple de projet utilisant cette convention.

OlivierM
la source
1

Un argument que je n'ai pas encore vu est qu'un préfixe tel que m_peut être utilisé pour empêcher le nom d'entrer en conflit avec #defineles macros 'd.

Regex recherche #define [a-z][A-Za-z0-9_]*[^(]dans /usr/include/term.hdes malédictions / ncurses.

yyny
la source