Cosa significa il prefisso variabile `m_`?


155

Vedo spesso m_prefisso usato per le variabili ( m_World, m_Sprites, ...) in tutorial, esempi e altro codice riguardato principalmente lo sviluppo del gioco.

Perché le persone aggiungono il prefisso m_alle variabili?



18
Prima di seguire indifferentemente l'esempio con la notazione ungherese, ti preghiamo di fare qualche controllo storico su cosa sia davvero la notazione ungherese. Perché nominare un iCounter int è semplicemente inutile. Ma nominare int xAnnotationPos e yAnnotationPos è ragionevole. Usa la versione semantica.
AkselK,

A volte, i moduli importati aggiungono funzioni e variabili in modo da avere meno probabilità di sovrascriverli con il proprio codice. È un modo di "riservare" i nomi per un uso specifico.
earthmeLon

3
Mentre la notazione "ungherese" viene spesso derisa in modo vizioso, il suo particolare sapore che denota portata variabile presenta alcuni vantaggi reali. Oltre a identificare l'ambito della variabile, impedisce le collisioni di nomi, come quando un locale, un parm e un membro hanno tutti lo stesso intento, e quindi lo stesso nome "semantico". Ciò può rendere più semplice e meno soggetta a errori la manutenzione di basi di codice di grandi dimensioni.
Hot Licks

8
Ci sono argomenti a favore e contro qualsiasi standard di codifica, ma la domanda chiede chiaramente a cosa serve m_, tuttavia metà delle risposte qui sono un commento sul perché tutti pensano che il loro attuale preferito sia il migliore.
CZ

Risposte:


108

Questa è una tipica pratica di programmazione per la definizione di variabili che sono variabili membro. Quindi, quando li usi in seguito, non è necessario vedere dove sono definiti per conoscerne l'ambito. Questo è ottimo anche se conosci già l'ambito e stai usando qualcosa come intelliSense , puoi iniziare con m_e viene mostrato un elenco di tutte le variabili del tuo membro. Parte della notazione ungherese, vedere la parte relativa all'ambito negli esempi qui .


51
Peggior argomento per una convenzione di denominazione, puoi semplicemente premere ctrl + spazio per intellisense.
orlp

11
@nightcracker anche se non mi piace il prefisso, intende dire che quando si digita m_ e quindi "CTRL + SPAZIO" (a meno che non sia automatico) si ottiene un elenco contenente solo i membri. Non è esattamente una buona ragione ma è un vantaggio.
Sidar,

13
Vale la pena ricordare che ci sono molti altri modi più o meno standard per fare la stessa cosa; "m_variable", "m_Variable", "mVariable", "_variable", "_Variable" ... in che modo 'migliore' o 'giusto' (o se farlo affatto) è un'argomentazione controversa e infruttuosa come ' spazi vs tab ". :)
Trevor Powell,

49
Preferisco solo usare "this->" - kinda rende "m_" ridondante ed è ancora migliore in quanto è applicato dal compilatore (in teoria puoi "m_" pop su qualsiasi tipo di variabile; non puoi farlo con "this-> "). Una parte di me vorrebbe che il C ++ si uniformasse semplicemente rendendo "questo->" obbligatorio. Ma questo va più nel mondo della discussione che nell'essere una risposta.

3
@LaurentCouvidou, non puoi davvero imporre che gli sviluppatori creino variabili membro con il prefisso di m_entrambi.
SomeWrites Riservato il

94

In Clean Code: A Handbook of Agile Software Craftsrafts c'è una raccomandazione esplicita contro l'uso di questo prefisso:

Inoltre, non è più necessario aggiungere un prefisso alle variabili membro m_. Le tue classi e funzioni dovrebbero essere abbastanza piccole da non averne bisogno.

C'è anche un esempio (codice C #) di questo:

Cattiva pratica:

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

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

Buona pratica:

public class Part
{
    private String description;

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

Contiamo con costrutti del linguaggio per fare riferimento a variabili membro nel caso di esplicita l'ambiguità ( cioè , descriptionmembro e descriptionparametri): this.


6
Il testo potrebbe essere "esiste una raccomandazione esplicita CONTRO l'uso di questo prefisso:"
Xofo

Sono così felice che qualcuno l'abbia scritto
dmitreyg

Un altro motivo è che in java getter / setter sono considerati getName / setName, quindi getM_name è errato e devi gestirli uno per uno.
Leon,

Grazie per aver scritto questo. Volevo solo sottolineare che il libro che hai citato è uscito da agosto 2008 - e trovo ancora questa cattiva pratica nel nuovo codice oggi (2019).
alexlomba87,

20

È pratica comune in C ++. Questo perché in C ++ non è possibile avere lo stesso nome per la funzione membro e la variabile membro e le funzioni getter sono spesso denominate senza il prefisso "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 il "membro". Il prefisso "_" è anche comune.

Non dovresti usarlo in linguaggi di programmazione che risolvono questo problema usando convenzioni / grammatica diverse.


11

Il m_prefisso viene spesso utilizzato per le variabili membro - penso che il suo principale vantaggio sia che aiuta a creare una chiara distinzione tra una proprietà pubblica e la variabile membro privata che la supporta:

int m_something

public int Something => this.m_something; 

Può aiutare ad avere una convenzione di denominazione coerente per il backup delle variabili e il m_prefisso è un modo per farlo - quello che funziona in linguaggi senza distinzione tra maiuscole e minuscole.

Quanto sia utile dipende dalle lingue e dagli strumenti che stai utilizzando. Gli IDE moderni con potenti strumenti di refactoring e intellisense hanno meno bisogno di convenzioni come questa, e non è certamente l'unico modo per farlo, ma vale la pena essere consapevoli della pratica in ogni caso.


5
Se devi scrivere this.nella tua lingua, m_è davvero inutile.
Ruslan,

@Ruslan m_è quello di distinguerlo dalla proprietà che esegue il backup, quindi this.Somethingper la proprietà rispetto this.m_somethingal membro di supporto. Non è una convenzione che preferisco me stesso, ma l'ho visto principalmente usato in linguaggi insensibili al maiuscolo (come VB).
Keith,

1
Perché no, this.Somethingper la proprietà e this.somethingper il supporto? O this._somethingper il supporto? this.m_somethingè ridondante. Lo uso in _somethingmodo da Somethingnon
scriverlo

@AustinWBryan vedi il mio commento precedente sui linguaggi senza distinzione tra maiuscole e minuscole. Sì, un _prefisso da solo farebbe il lavoro, ma m_è la convenzione. Non è uno che userei personalmente, ma se lo vedi nel codice era l'intento dell'autore.
Keith,

7

Come indicato nelle altre risposte, il m_prefisso viene utilizzato per indicare che una variabile è un membro della classe. Questo è diverso dalla notazione ungherese perché non indica il tipo di variabile ma il suo contesto.

Uso m_in C ++ ma non in altre lingue in cui 'this' o 'self' sono obbligatori. Non mi piace vedere 'this->' usato con C ++ perché ingombra il codice.

Un'altra risposta dice m_dsc"cattiva pratica" e "descrizione"; è "buona pratica" ma si tratta di un'aringa rossa perché il problema è l'abbreviazione.

Un'altra risposta dice che digitando thisIntelliSense compare, ma ogni IDE valido avrà un tasto di scelta rapida per far apparire IntelliSense per i membri della classe corrente.


"ma questa è un'aringa rossa" - Buon punto. Un confronto equo sarebbe m_descriptionvs description.
Battaglia

3

Come affermato in molte altre risposte, m_ è un prefisso che indica le variabili membro. È / era comunemente usato nel mondo C ++ e propagato anche in altre lingue, incluso Java.

In un IDE moderno è completamente ridondante poiché l'evidenziazione della sintassi rende evidente quali variabili sono locali e quali sono membri . Tuttavia, quando è apparso l'evidenziazione della sintassi alla fine degli anni '90, la convenzione era in circolazione da molti anni ed era stata stabilita (almeno nel mondo C ++).

Non so a quali tutorial ti riferisci, ma immagino che stiano usando la convenzione a causa di uno di questi due fattori:

  • Sono tutorial C ++, scritti da persone abituate alla convenzione m_, e / o ...
  • Scrivono il codice in testo semplice (monospaziato), senza evidenziare la sintassi, quindi la convenzione m_ è utile per rendere più chiari gli esempi.

Un esempio potrebbe essere questo: wiki.qt.io/How_to_Use_QSettings Dato che Qt Creator utilizza l'evidenziazione, potrebbe apparire la prima ipotesi. Un po 'diverso potrebbe essere un'altra convenzione che usa _object () per oggetti privati ​​di una classe e p_variable se è un puntatore poiché entrambi non sono highligted come io conosco e sembrano avere senso per me usarlo.
Ivanovic,

3

Lockheed Martin utilizza uno schema di denominazione a 3 prefissi con cui è stato meraviglioso lavorare, specialmente quando si legge il codice degli altri.

   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

Così...

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

Prendilo per quello che vale.


Eccezionale. Grazie per l '"esempio". Dove è davvero utile è quando si modificano 200.000 righe di codice.
jiveturkey,

1
Non c'è bisogno di diventare difensivi. Sto onestamente cercando di aiutarti mostrandoti che c'è un errore nella tua risposta. Vorrei essere più chiaro, quindi: non importa se hai 5 o 200000 righe di codice: il compilatore non ti consentirà di eseguire un'assegnazione con tipi di puntatore incompatibili. Quindi il punto sollevato nel commento è discutibile.
Cássio Renan,

Non intendevo diventare difensivo. Scusate.
jiveturkey,

È una variazione della notazione ungherese, che non ha senso nelle lingue moderne ...
doc

2

Per completare le risposte correnti e poiché la domanda non è specifica della lingua, alcuni progetti C usano il prefisso m_per definire le variabili globali specifiche di un file e g_per le variabili globali che hanno un ambito più ampio del file che vengono definite.
In questo caso, le variabili globali definite con il prefisso m_ devono essere definite come static.

Vedere la convenzione di codifica EDK2 (un'implementazione Open-Source UEFI) per un esempio di progetto che utilizza questa convenzione.


1

Un argomento che non ho ancora visto è che un prefisso come quello m_può essere usato per prevenire lo scontro tra nomi con #define'macro'.

Ricerca Regex per #define [a-z][A-Za-z0-9_]*[^(]in /usr/include/term.hda maledizioni / ncurses.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.