¿Qué significa el prefijo de variable `m_`?

154

A menudo veo m_prefijo utilizado para las variables ( m_World, m_Sprites, ...) en tutoriales, ejemplos y otros códigos relacionados principalmente con el desarrollo del juego.

¿Por qué la gente agrega prefijo m_a las variables?

Kravemir
fuente
18
Antes de seguir sin pensarlo con la notación húngara, por favor verifique la historia de lo que realmente es la notación húngara. Porque nombrar un iCounter int no tiene sentido. Pero nombrar un int xAnnotationPos y yAnnotationPos es razonable. Utiliza la versión semántica.
AkselK
A veces, los módulos importados prefijan funciones y variables para que sea menos probable que los sobrescriba con su propio código. Es una forma de 'reservar' nombres para un uso específico.
earthmeLon
3
Si bien la notación "húngara" a menudo se burla viciosamente, su sabor particular que denota alcance variable tiene algunas ventajas reales. Además de identificar el alcance de la variable, evita las colisiones de nombres, como cuando un local, un parm y un miembro tienen la misma intención y, por lo tanto, el mismo nombre "semántico". Esto puede hacer que el mantenimiento de bases de código grandes sea más simple y menos propenso a errores.
Hot Licks el
8
Hay argumentos a favor y en contra de cualquier estándar de codificación, pero la pregunta claramente pregunta para qué sirve m_, sin embargo, la mitad de las respuestas aquí son un comentario sobre por qué todos piensan que su favorito actual es el mejor.
cz

Respuestas:

108

Esta es una práctica de programación típica para definir variables que son variables miembro. Entonces, cuando los use más adelante, no necesita ver dónde están definidos para conocer su alcance. Esto también es genial si ya conoce el alcance y está usando algo como intelliSense , puede comenzar m_y se muestra una lista de todas sus variables miembro. Parte de la notación húngara, vea la parte sobre el alcance en los ejemplos aquí .

MichaelHouse
fuente
51
El peor argumento para una convención de nomenclatura, simplemente puede presionar ctrl + espacio para intellisense.
orlp
11
@nightcracker aunque no me gusta el prefijo, quiere decir que cuando escribes m_ y luego "CTRL + ESPACIO" (a menos que sea automático) obtienes una lista que solo contiene a tus miembros. No es exactamente una buena razón, pero es una ventaja.
Sidar
13
Vale la pena mencionar que hay muchas otras formas más o menos estándar de hacer lo mismo; "m_variable", "m_Variable", "mVariable", "_variable", "_Variable" ... de qué manera es 'mejor' o 'correcto' (o si hacerlo) es un argumento tan polémico e infructuoso como ' espacios vs pestañas '. :)
Trevor Powell
49
Prefiero simplemente usar "this->" - un poco hace que "m_" sea redundante y es aún mejor ya que el compilador lo aplica (en teoría, puede hacer estallar "m_" en cualquier tipo de variable; no puede hacer eso con "this-> "). Una parte de mí desea que C ++ simplemente se estandarice para hacer que "esto->" sea obligatorio. Pero eso va más en el mundo de la discusión que ser una respuesta.
3
@LaurentCouvidou, realmente no puedes hacer cumplir que los desarrolladores crean variables miembro con el prefijo m_.
SomeWritesReserved el
94

En Clean Code: A Handbook of Agile Software Craftsmanship hay una recomendación explícita contra el uso de este prefijo:

Tampoco necesita prefijar las variables miembro con m_más. Sus clases y funciones deben ser lo suficientemente pequeñas como para que no las necesite.

También hay un ejemplo (código C #) de esto:

Mala práctica:

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

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

Buena práctica:

public class Part
{
    private String description;

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

Contamos con construcciones de lenguaje para referirse a variables miembro en el caso de la ambigüedad de manera explícita ( es decir , descriptionmiembros y descriptionparámetros): this.

InfZero
fuente
66
La redacción podría ser "hay una recomendación explícita CONTRA el uso de este prefijo:"
Xofo
Estoy muy contento de que alguien lo haya escrito
dmitreyg
Otra razón es que en java getter / setter se supone que son getName / setName, por lo que getM_name es malo y debe manejarlos uno por uno.
Leon
Gracias por escribir esto. Solo quería señalar que el libro que citó salió desde agosto de 2008, y todavía encuentro esta mala práctica en el nuevo código hoy (2019).
alexlomba87
20

Es una práctica común en C ++. Esto se debe a que en C ++ no puede tener el mismo nombre para la función miembro y la variable miembro, y las funciones getter a menudo se nombran sin el prefijo "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_" indica para el "miembro". El prefijo "_" también es común.

No debe usarlo en lenguajes de programación que resuelvan este problema usando diferentes convenciones / gramática.

Doc
fuente
11

El m_prefijo se usa a menudo para las variables miembro; creo que su principal ventaja es que ayuda a crear una distinción clara entre una propiedad pública y la variable miembro privada que la respalda:

int m_something

public int Something => this.m_something; 

Puede ser útil tener una convención de nomenclatura coherente para las variables de respaldo, y el m_prefijo es una forma de hacerlo, una que funciona en lenguajes que no distinguen entre mayúsculas y minúsculas.

La utilidad de esto depende de los idiomas y las herramientas que esté utilizando. Los IDE modernos con herramientas de refactorización e intellisense fuertes tienen menos necesidad de convenciones como esta, y ciertamente no es la única forma de hacerlo, pero vale la pena estar al tanto de la práctica en cualquier caso.

Keith
fuente
55
Si tiene que escribir this.en su idioma, entonces m_es realmente inútil.
Ruslan
@Ruslan m_es distinguirlo de la propiedad que respalda, this.Somethingpor lo tanto, para la propiedad frente this.m_somethingal miembro de respaldo. No es una convención que prefiera, pero la he visto principalmente en lenguajes insensibles a mayúsculas (como VB).
Keith
1
¿Por qué no, this.Somethingpara la propiedad y this.somethingpara el respaldo? O this._somethingpara el respaldo? this.m_somethingEs redundante. Lo uso _somethingpara no escribirlo accidentalmente cuando voy a escribir Something, nada que ver con membresía o no
AustinWBryan
@AustinWBryan ve mi comentario anterior sobre lenguajes que no distinguen entre mayúsculas y minúsculas. Sí, un _prefijo por sí solo haría el trabajo, pero m_es la convención. No es uno que usaría personalmente, pero si lo ves en código, esa fue la intención del autor.
Keith
7

Como se indica en las otras respuestas, el m_prefijo se usa para indicar que una variable es un miembro de la clase. Esto es diferente de la notación húngara porque no indica el tipo de la variable sino su contexto.

Lo uso m_en C ++ pero no en otros lenguajes donde 'this' o 'self' es obligatorio. No me gusta ver 'this->' usado con C ++ porque satura el código.

Otra respuesta dice m_dsces "mala práctica" y "descripción"; es una "buena práctica" pero es un arenque rojo porque el problema es la abreviatura.

Otra respuesta dice que escribir thisaparece IntelliSense, pero cualquier buen IDE tendrá una tecla de acceso rápido para mostrar IntelliSense para los miembros de la clase actual.

Quentin 2
fuente
"pero esto es un arenque rojo" - Buen punto. Una comparación justa sería m_descriptionvs description.
Batalla
3

Como se indica en muchas otras respuestas, m_ es un prefijo que denota variables miembro. Es / fue comúnmente usado en el mundo C ++ y también se propagó a otros lenguajes, incluido Java.

En un IDE moderno es completamente redundante ya que el resaltado de sintaxis hace evidente qué variables son locales y cuáles son miembros . Sin embargo, cuando el resaltado de sintaxis apareció a fines de los 90, la convención había existido durante muchos años y estaba firmemente establecida (al menos en el mundo de C ++).

No sé a qué tutoriales se refiere, pero supongo que están usando la convención debido a uno de dos factores:

  • Son tutoriales de C ++, escritos por personas acostumbradas a la convención m_, y / o ...
  • Escriben código en texto plano (monoespaciado), sin resaltado de sintaxis, por lo que la convención m_ es útil para aclarar los ejemplos.
sergut
fuente
Un ejemplo podría ser este: wiki.qt.io/How_to_Use_QSettings Dado que Qt Creator IS utiliza el resaltado, puede aparecer la primera suposición. Un poco diferente podría ser otra convención usando _object () para objetos privados de una clase y p_variable si es un puntero, ya que ambos no están resaltados como sé y parecen tener sentido para mí usarlo.
Ivanovic
3

Lockheed Martin utiliza un esquema de nomenclatura de 3 prefijos con el que fue maravilloso trabajar, especialmente al leer el código de otros.

   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

Entonces...

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*
}

Tómelo por lo que vale.

jiveturkey
fuente
Increíble. Gracias por el "ejemplo". Lo que realmente resulta útil es cuando editas 200,000 líneas de código.
jiveturkey
1
No hay necesidad de ponerse a la defensiva. Sinceramente, estoy tratando de ayudarte mostrándote que hay un error en tu respuesta. Entonces, déjenme ser más claro: no importa si tiene 5 o 200000 líneas de código: el compilador no le permitirá hacer una asignación con tipos de puntero incompatibles. Entonces, el punto hecho en el comentario es discutible.
Cássio Renan
No pretendía salir a la defensiva. Lo siento.
jiveturkey
Es una variación de la notación húngara, que no tiene sentido en los idiomas modernos ...
doc
2

Para completar las respuestas actuales y como la pregunta no es específica del lenguaje, algunos proyectos C usan el prefijo m_para definir variables globales que son específicas de un archivo, y g_para las variables globales que tienen un alcance mayor que el archivo que están definidas.
En este caso, las variables globales definidas con prefijo m_ deben definirse como static.

Consulte la convención de codificación EDK2 (una implementación UEFI de código abierto) para ver un ejemplo de proyecto que usa esta convención.

OlivierM
fuente
1

Un argumento que aún no he visto es que m_se puede usar un prefijo como para evitar que el nombre entre en conflicto con #define'd macro's.

Búsqueda de expresiones regulares desde #define [a-z][A-Za-z0-9_]*[^(]in /usr/include/term.hcurses / ncurses.

yyny
fuente