Що означає префікс змінної `m_`?


154

Я часто бачу m_префікс , який використовується для змінних ( m_World, m_Sprites, ...) в навчальні посібники, приклади та іншого коду , в основному пов'язані з розвитком гри.

Чому люди додають префікс m_до змінних?



18
Перш ніж бездумно слідкувати за костюмом з угорською нотацією, будь ласка, перевірте історію того, що насправді є угорською нотацією. Тому що називати int iCounter просто безглуздо. Але називати int xAnnotationPos та yAnnotationPos є розумним. Використовуйте версію Semantic.
AkselK

Іноді імпортні модулі префіксують функції та змінні, так що ви рідше перезаписуєте їх власним кодом. Це спосіб «резервування» імен для конкретного використання.
earthmeLon

3
Незважаючи на те, що "угорські" позначення часто злісно висміюються, особливий аромат цього, що позначає змінну область дії, має деякі реальні переваги. На додаток до ідентифікації сфери змінної, вона запобігає зіткненням імен, як коли локальний, парм і член мають однаковий намір, а отже, те саме "семантичне" ім'я. Це може зробити обслуговування великих баз коду більш простим і менш схильним до помилок.
Гарячі лизання

8
Є аргументи «за» і «проти» будь-якого стандарту кодування, але питання чітко запитує, для чого це m_, але половина відповідей тут - це коментар, чому всі вважають, що їх поточний фаворит є найкращим.
cz

Відповіді:


108

Це типова практика програмування для визначення змінних, які є змінними-членами. Тож коли ви використовуєте їх пізніше, вам не потрібно бачити, де вони визначені, щоб знати їх сферу застосування. Це також чудово, якщо ви вже знаєте область, і ви використовуєте щось на зразок intelliSense , ви можете почати з m_цього списку та відобразити список усіх змінних вашого члена. Частина угорських позначень, частина про сферу застосування див. У прикладах тут .


51
Найгірший аргумент для конвенції про іменування коли-небудь, ви можете просто натиснути ctrl + пробіл для інтелігенції.
orlp

11
@nightcracker Eveven Хоча мені не подобається префікс, він хоче сказати, що коли ви наберете m_, а потім "CTRL + SPACE" (якщо це не автоматично), ви отримаєте список, що містить лише ваших членів. Не зовсім вагома причина, але це плюс.
Сидар

13
Варто зазначити, що існує багато інших більш-менш стандартних способів зробити те саме; "m_variable", "m_Variable", "mVariable", "_variable", "_Variable" ... який спосіб є "кращим" чи "правильним" (або чи потрібно це взагалі робити), настільки ж спірний і безрезультатний аргумент, як " пробіли та вкладки '. :)
Тревор Пауелл

49
Я вважаю за краще просто використовувати "this->" - свого роду робить "m_" надлишковим і ще краще, оскільки це застосовується компілятором (теоретично ви можете перескакувати "m_" на будь-якому типі змінних; не можу це зробити з "this-> "). Частина мене хоче, щоб C ++ було просто стандартизовано, щоб зробити "це->" обов'язковим. Але це йде більше у світ дискусії, ніж бути відповіддю.

3
@LaurentCouvidou, ти не можеш реально застосувати, що розробники створюють членські змінні з префіксом m_будь-якого.
SomeWritesЗарезервовано

94

У чистому коді: Довідник Agile Craftsmanship Software пропонує чітку рекомендацію щодо використання цього префікса:

Також вам більше не потрібно префіксувати змінні члена m_. Ваші класи та функції повинні бути досить маленькими, щоб вони вам не потрібні.

Також є приклад (код C #) цього:

Погана практика:

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

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

Гарна практика:

public class Part
{
    private String description;

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

Ми розраховуємо з конструкціями мови для позначення змінних - членів в разі явного неоднозначності ( тобто , descriptionчленів і descriptionпараметрів): this.


6
Формулювання може бути "Є явна рекомендація ПРОТИ використання цього префікса:"
Xofo

Я так радий, що хтось це написав
dmitreyg

Ще одна причина полягає в тому, що в java getter / setter передбачається getName / setName, тому getM_name погано, і вам потрібно обробляти їх по черзі.
Леон

Дякуємо, що написали це. Я просто хотів зазначити, що цитована вами книга вийшла з серпня 2008 року - і я все ще знаходжу цю погану практику в новому коді сьогодні (2019).
alexlomba87

20

Це звичайна практика на C ++. Це тому, що в C ++ ви не можете мати однакове ім’я для функції члена та змінної члена, а функції getter часто називаються без префіксу "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_" станів для "члена". Префікс "_" також поширений.

Не слід використовувати його в мовах програмування, які вирішують цю проблему, використовуючи різні конвенції / граматики.


11

m_Префікс часто використовуються для змінних - членів - Я думаю , його головна перевага полягає в тому, що вона допомагає створити чітку відмінність між суспільною власністю і приватною підтримкою змінного члена документа :

int m_something

public int Something => this.m_something; 

Це може допомогти скласти послідовну конвенцію іменування для резервного копіювання змінних, і m_префікс - це один із способів цього - той, який працює у нечутливих до регістру мовах.

Наскільки це корисно, залежить від мов та інструментів, якими ви користуєтесь. Сучасні ІДЕ з потужними інструментами рефактора та інтелісенсією мають меншу потребу в таких конвенціях, і це, звичайно, не єдиний спосіб зробити це, але варто бути обізнаним про практику в будь-якому випадку.


5
Якщо вам доведеться писати this.своєю мовою, то m_це справді марно.
Руслан

@ Руслан m_полягає в тому, щоб відрізнити його від властивості, яку він підтримує - так this.Somethingдля власності проти this.m_somethingдля підтримуючого члена. Я не віддаю перевагу цьому умові, але я в основному бачив, що він використовується у випадку нечутливих мов (наприклад, VB).
Кіт

1
Чому б і ні, this.Somethingдля майна та this.somethingпідкладки? Або this._somethingдля підкладки? this.m_somethingє зайвим. Я використовую _somethingтак, що я не випадково Something
набираю

@AustinWBryan дивіться мій попередній коментар про нечутливі до регістру мови. Так, _префікс самостійно зробив би цю роботу, але m_це умовність. Я б не використовував його особисто, але якщо ви бачите це в коді, це було задумом автора.
Кіт

7

Як зазначено в інших відповідях, m_префікс використовується для вказівки, що змінна є членом класу. Це відрізняється від угорського позначення тим, що вказується не тип змінної, а її контекст.

Я використовую m_в C ++, але не в деяких інших мовах, де "це" або "Я" є обов'язковим. Мені не подобається бачити "це->", що використовується у C ++, тому що це захаращує код.

Інша відповідь говорить m_dsc: "погана практика" та "опис". "хороша практика", але це червона оселедець, тому що проблема є в абревіатурі.

Ще одна відповідь говорить, що при введенні thisспливаючих даних IntelliSense, але будь-який хороший IDE матиме гарячу клавішу для появи спливаючих даних IntelliSense для нинішніх членів класу.


"але це червона оселедець" - Добрий момент. Порівняння справедливо було б m_descriptionпроти description.
Битва

3

Як зазначено в багатьох інших відповідях, m_ є префіксом, який позначає змінні члена. Він / широко застосовувався у світі C ++ і поширювався і на інші мови, включаючи Java.

У сучасному IDE це зовсім зайве, оскільки виділення синтаксису дає зрозуміти, які змінні є локальними, а які - членами . Однак до того часу, коли підсвічування синтаксису з'явилося наприкінці 90-х, конвенція існувала протягом багатьох років і була твердо встановлена ​​(принаймні, у світі С ++).

Я не знаю, до яких навчальних посібників ви звертаєтесь, але я здогадуюсь, що вони використовують конвенцію через один із двох факторів:

  • Це підручники C ++, написані людьми, звиклими до конвенції m_ та / або ...
  • Вони пишуть код у простому (односкладному) тексті без підкреслення синтаксису, тому умова m_ корисна, щоб зробити приклади більш зрозумілими.

Одним із прикладів може бути такий: wiki.qt.io/How_to_Use_QSettings Оскільки Qt Creator IS використовує виділення, може з’явитися перша здогадка. Трохи іншою може бути інша умова, що використовує _object () для приватних об'єктів класу та p_variable, якщо він є вказівником, оскільки обидва не мають високого рівня, як я знаю, і, здається, має сенс використовувати його.
Іванович

3

Lockheed Martin використовує 3-префіксну схему іменування, з якою було чудово працювати, особливо при читанні інших кодів.

   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

Так...

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

Візьміть це за те, що воно варте.


Дивовижно. Дякую за "приклад". Де це дуже корисно - це коли ви редагуєте 200 000 рядків коду.
jiveturkey

1
Не потрібно отримувати оборону. Я чесно намагаюся допомогти вам, показавши, що у вашій відповіді є помилка. Дозвольте зрозуміти, тоді: Не має значення, чи є у вас 5, або 200000 рядків коду: компілятор не дозволить вам виконувати завдання з несумісними типами вказівників. Тож пункт, викладений у коментарі, є суперечливим.
Кассіо Ренан

Не означав виходити як оборонний. Вибачте.
jiveturkey

Це варіація угорської нотації, яка не має сенсу в сучасних мовах ...
док

2

Для завершення поточних відповідей і оскільки питання не є мовним, деякі C-проекти використовують префікс m_для визначення глобальних змінних, специфічних для файлу - і g_для глобальних змінних, які мають масштаб більше, ніж визначений файл.
У цьому випадку глобальні змінні, визначені з префіксом, m_ повинні бути визначені як static.

Див. EDK2 (реалізація UEFI з відкритим кодом) для кодування проекту на прикладі проекту, що використовує цю конвенцію.


1

Один із аргументів, яких я ще не бачив, - це те, що такий префікс, як, наприклад, m_може бути використаний для запобігання зіткнення імені з #define'd макрос.

Шукати #define [a-z][A-Za-z0-9_]*[^(]в Regex за /usr/include/term.hдопомогою прокльонів / ncurses.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.