Co oznacza przedrostek zmiennej „m_”?

154

Często widzę m_prefiks używany dla zmiennych ( m_World, m_Sprites...) w samouczki, przykłady i innego kodu, związanych głównie z rozwojem gry.

Dlaczego ludzie dodają przedrostki m_do zmiennych?

kravemir
źródło
18
Zanim bezmyślnie podążasz za zapisem węgierskim, sprawdź historię, czym naprawdę jest notacja węgierska. Ponieważ nazywanie int iCounter jest po prostu bezcelowe. Ale nazwanie int xAnnotationPos i yAnnotationPos jest rozsądne. Użyj wersji semantycznej.
AkselK
Czasami zaimportowane moduły poprzedzają funkcje i zmienne, dzięki czemu istnieje mniejsze prawdopodobieństwo nadpisania ich własnym kodem. Jest to sposób „rezerwowania” nazw do określonego użytku.
earthmeLon
3
Chociaż notacja „węgierska” jest często złośliwie wyśmiewana, jej szczególny smak, który oznacza zmienny zakres, ma pewne realne zalety. Oprócz identyfikowania zakresu zmiennej zapobiega kolizjom nazw, tak jak wtedy, gdy lokalna, parm i element członkowski mają tę samą intencję, a zatem tę samą „semantyczną” nazwę. Może to sprawić, że utrzymanie dużych baz kodu będzie prostsze i mniej podatne na błędy.
Hot Licks
8
Istnieją argumenty za i przeciw każdemu standardowi kodowania, ale pytanie wyraźnie dotyczy tego, po co jest m_, ale połowa odpowiedzi tutaj to komentarz na temat tego, dlaczego wszyscy uważają, że ich obecny ulubiony jest najlepszy.
cz

Odpowiedzi:

108

Jest to typowa praktyka programistyczna służąca do definiowania zmiennych, które są zmiennymi składowymi. Więc kiedy używasz ich później, nie musisz widzieć, gdzie są zdefiniowane, aby poznać ich zakres. Jest to również świetne, jeśli znasz już zakres i używasz czegoś takiego jak IntelliSense , możesz zacząć od m_i zostanie wyświetlona lista wszystkich zmiennych składowych . Część notacji węgierskiej, patrz część dotycząca zakresu w przykładach tutaj .

MichaelHouse
źródło
51
Najgorszy argument przemawiający za konwencją nazewnictwa w historii, możesz po prostu nacisnąć ctrl + spacja, aby uzyskać inteligencję.
orlp
11
@nightcracker event - chociaż nie podoba mi się ten prefiks, ma na myśli to, że kiedy wpiszesz m_, a następnie „CTRL + SPACJA” (chyba że jest to auto), otrzymasz listę zawierającą tylko twoich członków. Nie do końca dobry powód, ale to plus.
Sidar
13
Warto wspomnieć, że istnieje wiele innych mniej lub bardziej standardowych sposobów na zrobienie tego samego; „m_variable”, „m_Variable”, „mVariable”, „_variable”, „_Variable” ... który sposób jest „najlepszy” lub „właściwy” (lub czy w ogóle) jest równie kontrowersyjny i bezowocny jak „ spacje vs tabulatory. :)
Trevor Powell
49
Wolę po prostu używać "this->" - trochę sprawia, że ​​"m_" jest zbędne i jest nawet lepsze, ponieważ jest wymuszane przez kompilator (teoretycznie możesz wstawić "m_" na dowolnym typie zmiennej; nie możesz tego zrobić z "this-> ”). Po części chciałbym, żeby C ++ po prostu ustandaryzował i uczynił „this->” obowiązkowym. Ale to bardziej dotyczy świata dyskusji niż odpowiedzi.
3
@LaurentCouvidou, nie możesz tak naprawdę wymusić na programistach tworzenia zmiennych składowych z prefiksem m_.
SomeWritesReserved
94

W Clean Code: A Handbook of Agile Software Craftsmanship znajduje się wyraźne zalecenie dotyczące używania tego przedrostka:

Nie musisz też już poprzedzać zmiennych m_składowych. Twoje klasy i funkcje powinny być na tyle małe, że ich nie potrzebujesz.

Istnieje również przykład (kod w C #) tego:

Zła praktyka:

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

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

Dobra praktyka:

public class Part
{
    private String description;

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

Liczymy z konstrukcjami językowymi w odniesieniu do zmiennych składowych w przypadku jawnie dwuznaczności ( tj , descriptionzarejestrował i descriptionparametrów) this.

InfZero
źródło
6
Sformułowanie mogłoby brzmieć „istnieje wyraźne zalecenie
przeciw
Tak się cieszę, że ktoś to napisał
dmitreyg
Innym powodem jest to, że w java przyjmuje się, że getter / setter to getName / setName, więc getM_name jest złe i trzeba je obsługiwać jeden po drugim.
Leon
Dzięki za napisanie tego. Chciałem tylko zaznaczyć, że książka, którą zacytowałeś, ukazała się od sierpnia 2008 roku - i nadal znajduję tę złą praktykę w nowym kodzie (2019).
alexlomba87
20

Jest to powszechna praktyka w C ++. Dzieje się tak, ponieważ w C ++ nie możesz mieć takiej samej nazwy dla funkcji składowej i zmiennej składowej, a funkcje pobierające są często nazywane bez przedrostka „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

Stany „m_” dla „członka”. Przedrostek „_” jest również powszechny.

Nie powinieneś go używać w językach programowania, które rozwiązują ten problem przy użyciu różnych konwencji / gramatyki.

doc
źródło
11

m_Prefiks jest często używany do zmiennych składowych - Myślę, że jego główną zaletą jest to, że pomaga tworzyć wyraźne rozróżnienie między własności publicznej i prywatnej zmiennej członkiem podkładzie go:

int m_something

public int Something => this.m_something; 

Pomocna może być spójna konwencja nazewnictwa dla zmiennych bazowych, a m_prefiks jest jednym ze sposobów osiągnięcia tego celu - takim, który działa w językach bez rozróżniania wielkości liter.

To, jak przydatne jest to, zależy od języków i narzędzi, których używasz. Nowoczesne IDE z silnymi narzędziami do refaktoryzacji i inteligencją mają mniejsze zapotrzebowanie na takie konwencje i z pewnością nie jest to jedyny sposób na zrobienie tego, ale w każdym przypadku warto mieć świadomość tej praktyki.

Keith
źródło
5
Jeśli musisz pisać this.w swoim języku, m_jest to naprawdę bezużyteczne.
Ruslan
@Ruslan the m_ma odróżnić ją od właściwości, której się cofa - tak więc this.Somethingw przypadku właściwości, a this.m_somethingw przypadku członka wspierającego. To nie jest konwencja, którą wolę siebie, ale widziałem ją głównie w językach niewrażliwych na wielkość liter (takich jak VB).
Keith
1
Dlaczego nie, this.Somethingze względu na majątek i this.somethingwsparcie? Lub this._somethingna podkład? this.m_somethingjest zbędny. Używam, _somethingaby przypadkowo nie wpisywać go, kiedy idę do pisania Something, nie ma to nic wspólnego z członkostwem lub nie
AustinWBryan
@AustinWBryan zobacz mój poprzedni komentarz dotyczący języków bez rozróżniania wielkości liter. Tak, sam _przedrostek wystarczyłby, ale m_taka jest konwencja. Nie jest to taki, którego bym użył osobiście, ale jeśli widzisz to w kodzie, taki był zamysł autora.
Keith
7

Jak stwierdzono w innych odpowiedziach, m_przedrostek służy do wskazania, że ​​zmienna jest członkiem klasy. Różni się to od notacji węgierskiej, ponieważ nie wskazuje typu zmiennej, ale jej kontekst.

Używam m_w C ++, ale nie w innych językach, w których „this” lub „self” jest obowiązkowe. Nie lubię, gdy „this->” jest używane w C ++, ponieważ zaśmieca kod.

Inna odpowiedź brzmi: m_dsc„zła praktyka” i „opis”; to „dobra praktyka”, ale to jest czerwony śledź, ponieważ problem polega na skrócie.

Inna odpowiedź mówi, że wpisywanie thiswyskakuje IntelliSense, ale każde dobre IDE będzie miało klawisz skrótu do wyskakiwania IntelliSense dla bieżących członków klasy.

Quentin 2
źródło
„ale to jest czerwony śledź” - słuszna uwaga. Porównanie sprawiedliwe byłoby m_descriptionvs description.
Bitwa
3

Jak stwierdzono w wielu innych odpowiedziach, m_ jest przedrostkiem oznaczającym zmienne składowe. Jest / był powszechnie używany w świecie C ++ i rozpowszechniany także w innych językach, w tym w Javie.

W nowoczesnym IDE jest to całkowicie zbędne, ponieważ podświetlanie składni pokazuje, które zmienne są lokalne, a które są członkami . Jednak do czasu, gdy podświetlanie składni pojawiło się pod koniec lat 90., konwencja istniała już od wielu lat i była mocno ustalona (przynajmniej w świecie C ++).

Nie wiem, do których tutoriali się odnosisz, ale zgadnę, że używają konwencji z powodu jednego z dwóch czynników:

  • Są to samouczki C ++, napisane przez ludzi przyzwyczajonych do konwencji m_ i / lub ...
  • Piszą kod w zwykłym tekście (o stałej szerokości), bez podświetlania składni, więc konwencja m_ jest przydatna, aby przykłady były bardziej przejrzyste.
sergut
źródło
Jednym z przykładów może być: wiki.qt.io/How_to_Use_QSettings Ponieważ kreator Qt JEST używa podświetlania, może pojawić się pierwsze przypuszczenie. Nieco inna może być inna konwencja, w której używa się funkcji _object () dla obiektów prywatnych klasy i zmiennej p_variable, jeśli jest to wskaźnik, ponieważ obie nie są podkreślone, jak wiem, i wydaje mi się, że ich użycie ma sens.
Ivanovic
3

Lockheed Martin używa schematu nazewnictwa z trzema prefiksami, z którym wspaniale się pracuje, zwłaszcza podczas czytania kodu innych osób.

   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

Więc...

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

Weź to za to, co jest warte.

jiveturkey
źródło
Niesamowite. Dzięki za „przykład”. Tam, gdzie jest to naprawdę przydatne, jest edytowanie 200 000 linii kodu.
jiveturkey
1
Nie musisz się bronić. Szczerze staram się Ci pomóc, pokazując, że w Twojej odpowiedzi jest błąd. Pozwólcie, że powiem więc bardziej jasno: nie ma znaczenia, czy masz 5 czy 200000 linii kodu: kompilator nie pozwoli ci wykonać przypisania z niekompatybilnymi typami wskaźników. Tak więc uwaga zawarta w komentarzu jest dyskusyjna.
Cássio Renan
Nie chciałem być defensywny. Przepraszam.
jiveturkey
To odmiana notacji węgierskiej, która nie ma sensu we współczesnych językach ...
dok
2

Aby uzupełnić bieżące odpowiedzi, a pytanie nie jest specyficzne dla języka, niektóre projekty C używają przedrostka m_do definiowania zmiennych globalnych, które są specyficzne dla pliku - i g_dla zmiennych globalnych, których zasięg jest większy niż plik, w którym są zdefiniowane.
W tym przypadku zmienne globalne zdefiniowane z przedrostkiem m_ powinny być zdefiniowane jako static.

Zobacz konwencję kodowania EDK2 (implementacja UEFI Open-Source), aby zapoznać się z przykładem projektu korzystającego z tej konwencji.

OlivierM
źródło
1

Jednym z argumentów, których jeszcze nie widziałem, jest to, że przedrostek taki jak m_może być używany do zapobiegania kolizji nazw z makrami #define„d”.

Wyszukiwanie wyrażeń regularnych #define [a-z][A-Za-z0-9_]*[^(]w /usr/include/term.hz curses / ncurses.

yyny
źródło