Защо да използвате префикси на членски променливи в C++ класове

Голяма част от C++ кода използва синтактични конвенции за маркиране на членски променливи. Често срещаните примери включват

  • m_memberName за публични членове (където изобщо се използват публични членове)
  • _memberName за лични членове или всички членове

Други се опитват да наложат използването на this->member винаги, когато се използва членска променлива.

Според моя опит повечето по-големи кодови бази не успяват да прилагат последователно такива правила.

В други езици тези конвенции са далеч по-малко разпространени. Виждам го само от време на време в Java или C# код. Мисля, че никога не съм го виждал в кода на Ruby или Python. По този начин изглежда има тенденция с по-модерните езици да не се използва специално маркиране за членски променливи.

Дали тази конвенция все още е полезна днес в C++ или е просто анахронизъм. Особено като се използва толкова непоследователно в библиотеките. Не показаха ли другите езици, че може и без членни префикси?


person VoidPointer    schedule 04.08.2009    source източник
comment
Предпочитам го; в сложни кодови бази може да е важно да знаете кои променливи са локални и кои не. Обикновено използвам префикса вместо принуждаването на this-›, което намирам за много допълнително писане и незадължително (докато наименуването ще ви принуди да го направите)   -  person Joe    schedule 04.08.2009
comment
Никога не сте го виждали в Ruby поради @ за атрибут и идиома за генериране на инструменти за достъп вместо директно използване на атрибути.   -  person Steve Jessop    schedule 04.08.2009
comment
Съгласно PEP 8 непубличните членски променливи трябва да имат префикс долна черта в Python (пример: self._something = 1).   -  person Nathan Osman    schedule 02.04.2013
comment
Не трябва ли да се използва осветяването на синтаксиса на редактора за идентифицирането им?   -  person too    schedule 14.07.2015
comment
Виждали сте еквивалента на this->member в кода на Python. В Python обикновено би било self.member и това не е само конвенция, то се изисква от езика.   -  person matec    schedule 14.05.2016
comment
Това може да е интересно за вас: github.com/isocpp/CppCoreGuidelines/blob/master/   -  person Kostiantyn Ponomarenko    schedule 18.06.2018


Отговори (29)


Трябва да внимавате с използването на водеща долна черта. Запазена е водеща долна черта преди главна буква в дума. Например:

_Фу

_L

са всички запазени думи, докато

_foo

_l

не са. Има и други ситуации, при които долната черта преди малките букви не е разрешена. В моя конкретен случай открих, че _L случайно е запазен от Visual C++ 2005 и сблъсъкът създаде някои неочаквани резултати.

Не съм наясно колко полезно е да се маркират локални променливи.

Ето връзка за това кои идентификатори са запазени: Какви са правилата за използване на долна черта в C++ идентификатор?

person Juan    schedule 04.08.2009
comment
Всъщност и _foo, и _l са запазени в обхвата на пространството от имена. - person ; 04.08.2009
comment
Но те са добре като имена на членски променливи. Не добавям долни черти, защото правилата са твърде объркващи и бях изгорял в миналото. - person Juan; 04.08.2009
comment
Това не са запазени думи. Те са запазени имена. Ако бяха запазени думи, изобщо не бихте могли да ги използвате. Тъй като те са запазени имена, можете да ги използвате, но на свой собствен риск. - person TonyK; 01.12.2010

Изцяло подкрепям добре направените префикси.

Мисля, че (системната) унгарска нотация е отговорна за повечето от "лошия рап", който получават префиксите.

Тази нотация е до голяма степен безсмислена в строго типизирани езици, напр. в C++ "lpsz", за да ви каже, че вашият низ е дълъг указател към низ, завършващ с нула, когато: сегментираната архитектура е древна история, низовете на C++ са според обичайната конвенция указатели към масиви с терминиран нула и всъщност не е толкова трудно да знаете, че "customerName" е низ!

Въпреки това, аз използвам префикси, за да уточня използването на променлива (по същество "Apps Hungarian", въпреки че предпочитам да избягвам термина Hungarian, тъй като има лоша и несправедлива връзка със System Hungarian), и това е много удобен подход за спестяване на време и намаляване на грешки.

Използвам:

  • м за членове
  • c за константи/само за четене
  • p за указател (и pp за указател към указател)
  • v за летлив
  • s за статично
  • i за индекси и итератори
  • e за събития

Когато искам да направя типа ясен, използвам стандартни суфикси (напр. List, ComboBox и т.н.).

Това прави програмиста наясно с използването на променливата винаги, когато я види/използва. Вероятно най-важният случай е "p" за указател (защото употребата се променя от var. на var-> и трябва да сте много по-внимателни с указателите - NULL, аритметика на указателя и т.н.), но всички останали са много удобни.

Например, можете да използвате едно и също име на променлива по няколко начина в една функция: (тук пример за C++, но той се прилага еднакво за много езици)

MyClass::MyClass(int numItems)
{
    mNumItems = numItems;
    for (int iItem = 0; iItem < mNumItems; iItem++)
    {
        Item *pItem = new Item();
        itemList[iItem] = pItem;
    }
}

Можете да видите тук:

  • Няма объркване между член и параметър
  • Няма объркване между индекс/итератор и елементи
  • Използване на набор от ясно свързани променливи (списък с елементи, указател и индекс), които избягват многото клопки на общи (неясни) имена като "брой", "индекс".
  • Префиксите намаляват въвеждането (по-кратки и работят по-добре с автоматично довършване) от алтернативи като "itemIndex" и "itemPtr"

Друга страхотна точка на итераторите "iName" е, че никога не индексирам масив с грешен индекс и ако копирам цикъл в друг цикъл, не трябва да преработвам една от променливите на индекса на цикъла.

Сравнете този нереалистично прост пример:

for (int i = 0; i < 100; i++)
    for (int j = 0; j < 5; j++)
        list[i].score += other[j].score;

(което е трудно за четене и често води до използване на "i", където "j" е предназначено)

с:

for (int iCompany = 0; iCompany < numCompanies; iCompany++)
    for (int iUser = 0; iUser < numUsers; iUser++)
       companyList[iCompany].score += userList[iUser].score;

(което е много по-четливо и премахва цялото объркване при индексирането. С автоматичното попълване в съвременните IDE това също е бързо и лесно за въвеждане)

Следващото предимство е, че кодовите фрагменти не изискват никакъв контекст, за да бъдат разбрани. Мога да копирам два реда код в имейл или документ и всеки, който чете този фрагмент, може да направи разликата между всички членове, константи, указатели, индекси и т.н. Не е нужно да добавям „о, и внимавайте, защото „данни“ е указател към указател“, защото се нарича „ppData“.

И по същата причина не е нужно да отмествам очите си от ред код, за да го разбера. Не е нужно да търся в кода, за да намеря дали „данни“ е локален, параметър, член или константа. Не е нужно да местя ръката си към мишката, за да мога да задържа показалеца върху „данни“ и след това да изчакам да изскочи подсказка (която понякога никога не се появява). Така програмистите могат да четат и разбират кода значително по-бързо, защото не губят време в търсене нагоре-надолу или в чакане.

(Ако не смятате, че губите време в търсене нагоре-надолу, за да изработите неща, намерете някакъв код, който сте написали преди година и не сте го разглеждали оттогава. Отворете файла и скочете около половината надолу, без да го прочетете . Вижте колко далеч можете да прочетете от тази точка, преди да не разберете дали нещо е член, параметър или локално. Сега преминете към друго произволно местоположение... Това е, което всички правим по цял ден, когато минаваме сами код на някой друг или се опитвате да разберете как да извикате тяхната функция)

Префиксът „m“ също така избягва (IMHO) грозната и многословна нотация „this->“ и несъответствието, което гарантира (дори и да внимавате, обикновено ще получите смесица от „this->data“ и „данни“ в същия клас, тъй като нищо не налага последователно изписване на името).

нотацията 'this' има за цел да разреши двусмислеността - но защо някой ще пише умишлено код, който може да бъде двусмислен? Неяснотата ще доведе до грешка рано или късно. И в някои езици „това“ не може да се използва за статични членове, така че трябва да въведете „специални случаи“ във вашия стил на кодиране. Предпочитам да имам едно просто правило за кодиране, което да се прилага навсякъде - изрично, недвусмислено и последователно.

Последното голямо предимство е с Intellisense и автоматично довършване. Опитайте да използвате Intellisense на Windows Form, за да намерите събитие - трябва да превъртите през стотици мистериозни методи на базовия клас, които никога няма да е необходимо да извиквате, за да намерите събитията. Но ако всяко събитие имаше префикс "e", те автоматично биха били изброени в група под "e". По този начин префиксът работи за групиране на членовете, константите, събитията и т.н. в списъка на intellisense, което прави много по-бързо и лесно намирането на имената, които искате. (Обикновено един метод може да има около 20-50 стойности (локални, параметри, членове, константи, събития), които са достъпни в неговия обхват. Но след като напиша префикса (искам да използвам индекс сега, така че пиша 'i. ..'), представят ми се само 2-5 опции за автоматично попълване. „Допълнителното въвеждане“, което хората приписват на префиксите и смислените имена, драстично намалява пространството за търсене и измеримо ускорява скоростта на разработка)

Аз съм мързелив програмист и горната конвенция ми спестява много работа. Мога да кодирам по-бързо и правя много по-малко грешки, защото знам как трябва да се използва всяка променлива.


Аргументи против

И така, какви са минусите? Типичните аргументи срещу префиксите са:

  • „Префиксните схеми са лоши/зли“. Съгласен съм, че "m_lpsz" и подобните му са зле обмислени и напълно безполезни. Ето защо бих посъветвал да използвате добре проектирана нотация, предназначена да поддържа вашите изисквания, вместо да копирате нещо, което е неподходящо за вашия контекст. (Използвайте правилния инструмент за работата).

  • „Ако променя начина на използване на нещо, трябва да го преименувам“. Да, разбира се, че го правите, това е същността на рефакторинга и защо IDE имат инструменти за рефакторинг, за да вършат тази работа бързо и безболезнено. Дори и без префикси, промяната на използването на променлива почти сигурно означава, че нейното име трябва да бъде променено.

  • „Префиксите просто ме объркват“. Както всеки инструмент, докато не се научите как да го използвате. След като мозъкът ви свикне с моделите на именуване, той автоматично ще филтрира информацията и наистина няма да имате нищо против, че префиксите вече са там. Но трябва да използвате стабилно схема като тази за седмица или две, преди наистина да станете „плавни“. И тогава много хора гледат стария код и започват да се чудят как изобщо са се справяли без добра префиксна схема.

  • „Мога просто да погледна кода, за да реша тези неща“. Да, но не е нужно да губите време да търсите другаде в кода или да си спомняте всеки малък детайл от него, когато отговорът е точно на мястото, върху което очите ви вече са фокусирани.

  • (Част от) тази информация може да бъде намерена, като просто изчакате да изскочи подсказка за моята променлива. да Когато се поддържа, за някои типове префикси, когато вашият код се компилира чисто, след изчакване, можете да прочетете описанието и да намерите информацията, която префиксът би предал незабавно. Смятам, че префиксът е по-прост, по-надежден и по-ефективен подход.

  • „Повече е писане“. Наистина ли? Още един цял герой? Или е така - с инструментите за автоматично довършване на IDE често ще се намали въвеждането, защото всеки префиксен знак стеснява значително пространството за търсене. Натиснете "e" и трите събития във вашия клас изскачат в intellisense. Натиснете "c" и се показват петте константи.

  • „Мога да използвам this-> вместо m. Е, да, можете. Но това е просто много по-грозен и многословен префикс! Само че носи много по-голям риск (особено в екипи), тъй като за компилатора е по избор и следователно използването му често е непоследователно. m от друга страна е кратък, ясен, ясен и незадължителен, така че е много по-трудно да се правят грешки при използването му.

person Community    schedule 04.08.2009
comment
Искам да кажа, че съм чел, че проблемът с Hungarien Notation просто е резултат от това, че Simonyi е бил неразбран. Той написа, че префиксът трябва да се използва за указване на типа на променлива, където той имаше предвид тип като нещо, а не буквален тип данни. По-късно момчетата от платформата в Microsoft го взеха и измислиха lpsz... а останалото е история... - person VoidPointer; 05.08.2009
comment
s е за статичен, звучи доста като лошата форма на унгарски за мен. - person jalf; 24.08.2011
comment
Тогава не го използвайте... Освен ако не смятате, че вашето използване на променливата може да бъде повлияно от знанието, че тя е статична... - person Jason Williams; 06.12.2011
comment
lps може да е излишен, но z не е. Със сигурност е добре да знаете дали даден низ е завършен с нула или не. - person user541686; 23.04.2012
comment
@Mehrdad: Не мисля, че z е много често полезен в език като C++, където този вид детайли за изпълнение на ниско ниво трябва да бъдат капсулирани в клас, но в C (където нулевото прекъсване е важна разлика) съм съгласен с теб . IMO всяка схема, която използваме, трябва да бъде адаптирана според изискванията, за да отговаря най-добре на собствените ни нужди - Така че, ако нулевото прекъсване засяга вашето използване на променливата, няма нищо лошо да декларирате z като полезен префикс. - person Jason Williams; 23.04.2012
comment
The most important case is "p" for pointer (because the usage changes from var. to var-> and you have to be much more careful with pointers. Напълно не съм съгласен. Ако използвам указател погрешно, той просто няма да се компилира (void* обаче може да е изключение за двойни указатели). И цялото -> върху . е достатъчно, за да ми каже, че е указател. Освен това, ако използвате автоматично довършване, вашият редактор вероятно има подсказки за декларации, елиминирайки необходимостта от префикс за информация за променливи. Независимо от това, добър отговор. - person Thomas Eding; 14.11.2012
comment
@Thomas: Всички добри точки. Някои ползи са силни, други по-слаби. По-силните случаи за p са за множество индиректности (X срещу pX срещу ppX) и аритметика на указателя (X++ срещу pX++ срещу *pX++), където знанието, че нещо е указател, е жизненоважно. За мен другите случаи все още са полезни - компилирането или подсказките са IMO просто по-малко ефективни начини за определяне дали променливата е указател (и другите минуси: подсказките не могат да бъдат копирани и поставени в примери извън вашата IDE и т.н.) . - person Jason Williams; 14.11.2012
comment
Гласуван за ясните, изчерпателни и интересни обяснения, но тук няма много подсказване как това спестява време в C++ ВЪВ ВРЕМЕ остава до голяма степен неизползвано в много други езици. - person ; 21.06.2013
comment
Също така бих добавил n за базирани на 1 числа, бройки и индекси. Доказано е много полезно за мен. За да бъдем честни, всички индекси трябва да са базирани на 0 (и да имат префикс i), но нещата се случват. Префиксът n помага за улавяне на грешки с аритметика на индекса. Например, int iLastItem = nDataItems - 1; трябва да изглежда добре за вашата вътрешна проверка на типа, докато m_TreeIndices[nLeftChild] = (iParent >= 1) ? iRightChild : null; изобщо не трябва. - person ulidtko; 08.08.2014
comment
Една от хубавите точки на auto е да не се ангажирате с някакъв тип данни. Странно, че трябва да поставим това в имената на променливите сега. - person Korchkidu; 09.01.2015
comment
@Korchkidu: auto/var може да бъде полезно, когато типовете са неизвестни, но повечето хора ги използват, за да бъдат мързеливи (избягвайте да въвеждате голямото дълго име на тип) и това въвежда точно с какъв тип работя тук? проблем, за чието разрешаване помагат префиксите. Скриването на известни типове зад ненужни автомати е много безполезна практика, тъй като замъглява кода. - person Jason Williams; 09.01.2015
comment
@JasonWilliams: Тези дни преработвах много код. Иска ми се да използвам автоматично повече. И не само за по-малко писане. Auto ви принуждава да не се обвързвате с някакъв тип. Това наистина помага в дългосрочен план. IMHO разбира се. И да не знаете с кой тип работите не е проблем, всъщност е хубава функция. - person Korchkidu; 10.01.2015
comment
По отношение на именуването, веднага щом видя numItems, настръхвам. Променливите не трябва да бъдат (подразбиращи се) предложни фрази (брой (на) елементи). По-скоро те трябва да са съществителни имена или съществителни фрази, напр. itemCount. - person Reid Ellis; 19.02.2015
comment
Това е елемент от граматиката, който е правилен, но до голяма степен неуместен по отношение на това дали хората, които четат този код, ще разберат намерението ми?. Мисля, че и numItems/itemCount са добри, въпреки че като цяло четливостта произтича от използването на естествена форма, докато yodaSpeak я намалява. (Настрана: count не е просто съществително, то е и глагол. Помислете за IEnumerable.Count на .Net - това връща ли броя на елементите в колекция или изброява колекцията и всъщност брои колко елемента има? Това е много важно разграничение, което може да е причина за някои ужасяващи проблеми с производителността) - person Jason Williams; 19.02.2015
comment
Препоръчително ли е да се използва префикс p и за интелигентни указатели? Напр.: std::unique_ptr<MyObject> pMyObject; - person Alexandru Irimiea; 03.10.2015
comment
Зависи от вас, но бих казал, че все още е указател, така че бих използвал префикс p за последователност... или ако смятате, че е важно да разграничите интелигентните указатели от обикновените, използвайте различен префикс - e.b. може да предпочетете p за интелигентни указатели и нещо като d за опасни!) - person Jason Williams; 05.10.2015
comment
Благодаря за отговора. Приемам твоя стил. Когато се прилагат няколко префикса, включвате ли всички, напр. mpsMyVar? Предполагам по азбучен ред? - person DBedrenko; 28.03.2016
comment
@SpaghettiCat: Добър въпрос. За C++, да (напр. 'p' е локален указател, 'mp' е указател на член, така че има значителна разлика). В C# const или static предполага, че е член, така че просто използвам 'm', 'c' или 's' самостоятелно. Така че коригирам схемата, за да пасне най-добре на всеки език, на който я използвам. Подредете ги както предпочитате, просто се опитайте да бъдете последователни, - person Jason Williams; 29.03.2016
comment
Мислех си, че прилагането на тази конвенция към публични членове не е добро, защото прави API, предоставен на другите, да изглежда по-малко чист. Не всеки ще разбере конвенцията и има потенциал да обърка. Така че ще следвам варианта на Android където публичните членове не са с префикс m (... не съм сигурен дали не трябва да прилагам и другите префикси...) - person DBedrenko; 04.05.2016
comment
@SpaghettiCat: Това описание се основава на предположението, че класовете използват капсулиране, т.е. че променливите-членове никога не са публични. За да изложим членска променлива на външни извикващи, бихме предоставили средство за достъп или свойство (към което схемата за префиксиране на членска променлива обикновено не би била приложена). - person Jason Williams; 04.05.2016
comment
След като работих малко със C++, виждам една причина, поради която префиксирането е по-популярно в този език. Това е така, защото членските променливи и членските функции споделят едно и също пространство от имена, за разлика от Java и по-модерните езици. По-бързо ти свършват имената. Всъщност е доста досадно. - person sourcedelica; 09.12.2016
comment
за константи е по-добре да се използва без префикс, но всички букви са главни - CONSTANT_VARIABLE - person user924; 19.03.2018
comment
@user924: Всички главни/долни черти са били популярни в миналото, така че ще видите, че се използват много, но вече не се считат за най-добра практика. Те правят кода (и документацията) по-малко четлив и много среди (C, C++, C#, VB, Java) придават специално значение на долните черти. Използването на схема за префиксиране е по-последователно и означава по-малко работа при рефакторинг на член между константа, свойство или променлива. Той също така ви позволява да разграничите константа, само за четене и макрос. Можете да използвате каквато схема желаете: просто бих ви насърчил да помислите за причината да предпочетете тази схема. - person Jason Williams; 21.03.2018
comment
@jalf: Защо мислиш, че s за статично е лошо? - person Oleksa; 26.06.2020
comment
@Jason Williams: Какво използвате за C масив? mArray, pArray или нещо друго? - person antho; 22.10.2020
comment
@antho: Склонен съм да използвам суфикс за списъци (от всякаква форма, т.е. масиви, колекции от списъци, свързани списъци - така че масив от превозни средства ще бъде vehicleList). Всеки префикс трябва да изяснява използването на масива (m за член и т.н.). Помислете: даването на всеки низ на префикс p само защото технически е указател към масив от char обикновено не би добавило стойност (обикновено не е необходимо да използваме низове като масиви), така че обикновено не бих използвал префикс, но ако Използвах указател към символ, за да преминавам през знаците в низ, абсолютно бих използвал префикс p, за да изясня това. - person Jason Williams; 26.10.2020
comment
Добре, благодаря, комбинацията от суфикс и префикс може да е добра. Благодаря за съвета - person antho; 26.10.2020
comment
Изобщо не харесвам този стил на кодиране. Всички суфикси са субективни и могат да се отнасят за всеки тип променлива в зависимост от кодера (както току-що демонстрирахте), докато простото използване на this-› е ясно и недвусмислено. Да не говорим, че този стил на суфикс просто внася шум в кодовите бази, които предпочитат използването на snake_case за съгласуваност със стандартната библиотека. Като се има предвид това, предпочитам да избягвам суфиксите. - person Cuadrix; 25.12.2020

Обикновено не използвам префикс за членски променливи.

Преди използвах префикс m, докато някой не посочи, че „C++ вече има стандартен префикс за членски достъп: this->.

Така че това е, което използвам сега. Тоест, когато има неяснота, добавям префикса this->, но обикновено не съществува неяснота и мога просто да се позова директно на името на променливата.

За мен това е най-доброто от двата свята. Имам префикс, който мога да използвам, когато ми трябва, и съм свободен да го оставя, когато е възможно.

Разбира се, очевидното противодействие на това е "да, но тогава не можете да видите с един поглед дали променливата е член на клас или не".

На което аз казвам "и какво от това? Ако трябва да знаете това, вашият клас вероятно има твърде много състояние. Или функцията е твърде голяма и сложна".

На практика установих, че това работи изключително добре. Като допълнителен бонус ми позволява лесно да популяризирам локална променлива към член на класа (или обратното), без да се налага да я преименувам.

И най-доброто от всичко е, че е последователен! Не е нужно да правя нещо специално или да помня някакви конвенции, за да поддържам последователност.


Между другото, вие не трябва да използвате водещи долни черти за членовете на вашия клас. Доближавате се неудобно до имена, които са запазени от изпълнението.

Стандартът запазва всички имена, започващи с двойна долна черта или долна черта, последвана от главна буква. Той също така запазва всички имена, започващи с една долна черта в глобалното пространство на имена.

Така че член на класа с водеща долна черта, последвана от малка буква, е законен, но рано или късно ще направите същото с идентификатор, започващ с главни букви, или по друг начин ще нарушите някое от горните правила.

Така че е по-лесно просто да избягвате водещите долни черти. Използвайте постфикс долна черта или m_ или само m префикс, ако искате да кодирате обхват в името на променливата.

person jalf    schedule 04.08.2009
comment
Така че член на класа с водеща долна черта, последвана от малка буква, е законен, но рано или късно ще направите същото с идентификатор, започващ с главни букви, или по друг начин ще нарушите някое от горните правила. -- променливите на члена на класа не са в глобалното пространство на имената, така че долната черта в началото е безопасна, независимо дали е последвана от малка или главна буква. - person mbarnett; 08.09.2011
comment
@mbarnett: Не, долната черта, последвана от главни букви, е запазена като цяло, а не само в глобалното пространство на имената. - person jalf; 08.09.2011
comment
изненадан, че гласът на този отговор е по-малък от този с префикса. - person Marson Mao; 02.09.2014
comment
Съгласен съм с този отговор, просто използвайте this->, ако трябва да посочите, че това е членска променлива, или не, това също е добре. - person David; 11.01.2017
comment
Освен това не е необходимо да документирате своята конвенция, за да дадете своя код на други хора. Всички разбират какво означава this->. - person Caduchon; 21.09.2017
comment
Двойната долна черта е запазена във всяка позиция, не само в началото на името. - person Ruslan; 21.09.2017
comment
В подкрепа на това: C++ Core Guidelines също не използват префикси в своите примери: isocpp.github.io/CppCoreGuidelines /CppCoreGuidelines - person Sascha; 07.11.2017

Предпочитам постфиксни долни черти, като такива:

class Foo
{
   private:
      int bar_;

   public:
      int bar() { return bar_; }
};
person jkeys    schedule 04.08.2009
comment
Аз също. Също така давам същото име на аксесоарите/мутаторите. - person Rob; 04.08.2009
comment
интересно В началото изглежда малко грозно, но виждам как може да бъде полезно. - person ya23; 16.11.2009
comment
Бих казал, че е много по-малко грозен от: mBar или m_bar. - person sydan; 21.04.2015
comment
но тогава имате vector<int> v_; и писането на v_.push_back(5) също е доста грозно - person avim; 30.04.2015
comment
Това е стилът на Google C++. - person Justme0; 26.11.2015

Напоследък предпочитам m_ префикс, вместо да нямам префикс, причините не са толкова, че е важно да се маркират членски променливи, а че избягва двусмислието, да речем, че имате код като:

void set_foo(int foo) { foo = foo; }

Това по причина не работи, разрешено е само едно foo. Така че вашите възможности са:

  • this->foo = foo;

    Не ми харесва, тъй като причинява засенчване на параметри, вече не можете да използвате g++ -Wshadow предупреждения, също така е по-дълго за въвеждане от m_. Също така все още се натъквате на конфликти при именуване между променливи и функции, когато имате int foo; и int foo();.

  • foo = foo_; or foo = arg_foo;

    Използвам това от известно време, но това прави списъците с аргументи грозни, документацията не би трябвало да се занимава с недвусмислеността на имената при изпълнението. Тук също съществуват конфликти при именуване между променливи и функции.

  • m_foo = foo;

    Документацията на API остава чиста, не получавате двусмислие между членските функции и променливите и е по-кратък за въвеждане от this->. Единственият недостатък е, че прави POD структурите грозни, но тъй като POD структурите не страдат от двусмислието на името на първо място, не е необходимо да го използвате с тях. Наличието на уникален префикс също прави няколко операции за търсене и замяна по-лесни.

  • foo_ = foo;

    Повечето от предимствата на m_ се прилагат, но аз го отхвърлям по естетически причини, долната черта в края или в началото просто прави променливата да изглежда непълна и небалансирана. m_ просто изглежда по-добре. Използването на m_ също е по-разширимо, тъй като можете да използвате g_ за глобални и s_ за статики.

PS: Причината, поради която не виждате m_ в Python или Ruby, е, че и двата езика налагат собствения си префикс, Ruby използва @ за членски променливи, а Python изисква self..

person Grumbel    schedule 29.08.2009
comment
за да бъдем честни, пропуснали сте поне 2 други опции, напр. (a) използвайте пълни имена като foo само за членове и вместо това използвайте еднобуквени или кратки имена за параметри или други локални/изхвърляния, като int f; или (b) добавете префикс към параметрите или други локални стойности с нещо. все пак добра точка за m_ и шушулки; самостоятелно стигнах до предпочитание да следвам и двете насоки в по-голямата си част. - person underscore_d; 28.01.2016
comment
@underscore_d Имената на параметрите са част от публичния интерфейс на клас. Това трябва да е последното място, където добавяте странни правила за именуване. Освен това еднобуквените имена на променливи са ужасни и трябва да се избягват на всяка цена с много малко изключения (i в цикъл). - person Dan Bechard; 13.02.2021

Когато четете функция член, да знаете кой "притежава" всяка променлива е абсолютно важно за разбирането на значението на променливата. Във функция като тази:

void Foo::bar( int apples )
{
    int bananas = apples + grapes;
    melons = grapes * bananas;
    spuds += melons;
}

...достатъчно лесно е да се види откъде идват ябълките и бананите, но какво ще кажете за гроздето, пъпешите и пъпешите? Трябва ли да търсим в глобалното пространство на имената? В декларацията на класа? Променливата член на този обект ли е или член на класа на този обект? Без да знаете отговора на тези въпроси, не можете да разберете кода. И в по-дълга функция дори декларациите на локални променливи като ябълки и банани могат да се изгубят в разбъркването.

Добавянето на последователен етикет за глобални, членски променливи и статични членски променливи (може би съответно g_, m_ и s_) незабавно изяснява ситуацията.

void Foo::bar( int apples )
{
    int bananas = apples + g_grapes;
    m_melons = g_grapes * bananas;
    s_spuds += m_melons;
}

В началото може да отнеме известно време, за да свикнете с тях, но тогава какво в програмирането не? Имаше ден, когато дори { и } ви изглеждаха странни. И след като свикнете с тях, те ви помагат да разберете кода много по-бързо.

(Използването на "this->" на мястото на m_ има смисъл, но е още по-продължително и визуално разрушително. Не го виждам като добра алтернатива за маркиране на всички употреби на променливи-членове.)

Възможно възражение срещу горния аргумент би било разширяването на аргумента до типове. Може също да е вярно, че познаването на типа на променливата "е абсолютно необходимо за разбирането на значението на променливата." Ако това е така, защо не добавите префикс към името на всяка променлива, който идентифицира нейния тип? С тази логика ще получите унгарска нотация. Но много хора намират унгарската нотация за трудоемка, грозна и безполезна.

void Foo::bar( int iApples )
{
    int iBananas = iApples + g_fGrapes;
    m_fMelons = g_fGrapes * iBananas;
    s_dSpuds += m_fMelons;
}

Унгарският не ни казва нещо ново за кода. Сега разбираме, че във функцията Foo::bar() има няколко неявни преобразувания. Проблемът с кода сега е, че стойността на информацията, добавена от унгарските префикси, е малка спрямо визуалната цена. Системата за типове C++ включва много функции, които помагат на типовете или да работят добре заедно, или да извеждат предупреждение или грешка на компилатора. Компилаторът ни помага да се справяме с типове - не се нуждаем от нотация, за да го направим. Достатъчно лесно можем да заключим, че променливите във Foo::bar() вероятно са числови и ако това е всичко, което знаем, това е достатъчно, за да придобием общо разбиране за функцията. Следователно стойността на познаването на точния тип на всяка променлива е относително ниска. И все пак грозотата на променлива като "s_dSpuds" (или дори само "dSpuds") е голяма. И така, анализът на разходите и ползите отхвърля унгарската нотация, докато ползата от g_, s_ и m_ превъзхожда разходите в очите на много програмисти.

person OldPeculier    schedule 21.10.2011
comment
Благодаря за s_ идеята. Изглежда много полезно и някак си никога не ми е хрумвало. - person Chris Olsen; 04.05.2020

Не мога да кажа колко разпространено е това, но лично аз винаги (и винаги съм) поставял пред променливите член с 'm'. напр.:

class Person {
   .... 
   private:
       std::string mName;
};

Това е единствената форма на префикс, която използвам (много съм против унгарската нотация), но ми помогна през годините. Като настрана, обикновено ненавиждам използването на долни черти в имената (или където и да е другаде по този въпрос), но направете изключение за имената на макроси на предпроцесора, тъй като те обикновено са главни букви.

person Community    schedule 04.08.2009
comment
Проблемът с използването на m вместо m_ (или _) е, че с текущата мода за камилски регистър затруднява четенето на някои имена на променливи. - person Martin Beckett; 04.08.2009
comment
Имам хитър план за справяне с това - не използвам камилска кутия. - person ; 04.08.2009
comment
@Neil аз съм с теб. @mgb: Мразя имена, започващи с '_' Това е просто покана нещата да се объркат в бъдеще. - person Martin York; 04.08.2009
comment
@Neil: Коя конвенция използвате тогава, ако не използвате долна черта и не използвате camelcase? - person jalf; 04.08.2009
comment
@jalf Имена на класове и членски променливи според примера по-горе. Функции като имена на класове. Локални променливи и параметри, всички с малки букви, с кратки имена - person ; 04.08.2009
comment
@jalf и аз трябваше да кажем многословни имена на класове/функции като това: DepositBankAccount. - person ; 04.08.2009
comment
@neil: Какво е DepositBankAccount, ако не е камила? - person mmmmmmmm; 04.08.2009
comment
Мислех, че камилският случай е депозитна банкова сметка. Или аз се обърквам? - person ; 04.08.2009
comment
ААА разбирам. Доколкото знам, depositBankAccount е камилски случай и мисля, че най-често срещаното име за DepositBankAccount е Pascal-case? (Никога не съм използвал Pascal, но доста често съм чувал това да се описва като Pascal-case.) - person jalf; 05.08.2009
comment
@jalf За първи път научих Pascal през 1980 г. и тогава хората използваха смесица от начини за наименуване на нещата. Delphi на Borland (вероятно единственият оцелял Pascal) използва стила DepositBankAccount, но също и това, което трябва да е най-влиятелната технология от всички тях - Windows API. - person ; 05.08.2009
comment
@neil: Не знам точно и просто мислех, че и depositBankAccount, и DepositBankAccount са камилски случай. Нека да видим какво казва wikipedia... Хей! Те казват същото! Но дали Уикипедия е авторитетен източник за това? - person mmmmmmmm; 05.08.2009
comment

Прекарайте показалеца към първия елемент в матрицата и размера.

- person ; 05.08.2009
comment
@neil: Мисля, че има много повече конвенции за именуване, отколкото има имена. (Сигурен съм, че дори има хора, които комбинират долна черта с главни букви (Deposit_Bank_Account) и съм сигурен, че няма име за това :-) - person mmmmmmmm; 05.08.2009
comment
Моето разбиране беше, че това е camelCase, което прави използването само на m за променливи като „apData“ объркващо - става „mapData“, а не „m_apData“. Използвам _camelCase за защитени/частни членски променливи, защото се откроява - person Martin Beckett; 05.09.2009
comment
@rstevens: Мислех, че This_Was_Called_Ada (кодът на Ada е единственото място, където съм виждал тази конвенция) - person Dan; 03.03.2010
comment
@MartinBeckett: Трябва да изписвате a с главна буква в този сценарий - иначе не го правите правилно. mApData (m префикс, тогава името на променливата е apData). - person Platinum Azure; 21.10.2011

Основната причина за префикс на член е да се прави разлика между локална функция член и променлива член със същото име. Това е полезно, ако използвате getters с името на нещото.

Обмисли:

class person
{
public:
    person(const std::string& full_name)
        : full_name_(full_name)
    {}

    const std::string& full_name() const { return full_name_; }
private:
    std::string full_name_;
};

Членската променлива не може да бъде наречена full_name в този случай. Трябва да преименувате функцията член на get_full_name() или да украсите променливата член по някакъв начин.

person Community    schedule 05.08.2009
comment
Това е причината да поставям префикс. Според мен foo.name() е много по-четлив от foo.get_name(). - person Terrabits; 14.07.2016

Не мисля, че един синтаксис има реална стойност пред друг. Всичко се свежда, както споменахте, до еднаквост в изходните файлове.

Единственият момент, в който намирам такива правила за интересни, е когато имам нужда от 2 неща с еднакви имена, например:

void myFunc(int index){
  this->index = index;
}

void myFunc(int index){
  m_index = index;
}

Използвам го, за да разгранича двете. Освен това, когато обвивам повиквания, например от Windows Dll, RecvPacket(...) от Dll може да бъде обвит в RecvPacket(...) в моя код. В тези конкретни случаи използването на префикс като "_" може да направи двете да изглеждат еднакви, лесно да се идентифицира кое е кое, но различно за компилатора

person Eric    schedule 04.08.2009

Някои отговори се фокусират върху рефакторинга, а не върху конвенциите за именуване, като начин за подобряване на четливостта. Не чувствам, че едното може да замени другото.

Познавам програмисти, които се чувстват неудобно да използват локални декларации; те предпочитат да поставят всички декларации в горната част на блок (както в C), така че да знаят къде да ги намерят. Открих, че там, където обхватът позволява това, декларирането на променливи там, където са използвани за първи път, намалява времето, което прекарвам в поглеждане назад, за да намеря декларациите. (Това важи за мен дори за малки функции.) Това ме улеснява да разбера кода, който гледам.

Надявам се, че е достатъчно ясно как това е свързано с конвенциите за именуване на членовете: Когато членовете имат еднакъв префикс, изобщо не трябва да поглеждам назад; Знам, че декларацията дори няма да бъде намерена в изходния файл.

Сигурен съм, че не съм започнал да предпочитам тези стилове. И все пак с течение на времето, работейки в среди, където те се използват последователно, оптимизирах мисленето си, за да се възползвам от тях. Мисля, че е възможно много хора, които в момента се чувстват неудобно с тях, също да ги предпочетат, предвид постоянната употреба.

person Dan Breslau    schedule 04.08.2009

Тези конвенции са точно това. Повечето магазини използват кодови конвенции, за да улеснят четливостта на кода, така че всеки да може лесно да погледне част от кода и бързо да дешифрира между неща като публични и частни членове.

person Mr. Will    schedule 04.08.2009
comment
между неща като публични и частни членове - колко често е това наистина? не си спомням да съм го виждал, но от друга страна, не обикалям да преглеждам кодови бази или нещо подобно. - person underscore_d; 28.01.2016
comment
Не го правя в собственото си кодиране, но съм работил на места, където трябваше да го направим въз основа на техните ръководства за кодова конвенция. Предпочитам да не го правя, тъй като почти всички IDE ще показват частни променливи с различен цвят. - person Mr. Will; 28.01.2016
comment
Хм, предполагам, че се случва само в ситуации, различни от моята. Обикновено използвам или classes, чиито всички членове са private/protected, или POD structs, всички чиито променливи са public (и често също const). Така че никога не трябва да се чудя за нивото на достъп на даден член. - person underscore_d; 28.01.2016

Други се опитват да наложат използване на този->член винаги, когато се използва членска променлива

Това обикновено е защото няма префикс. Компилаторът се нуждае от достатъчно информация, за да разреши въпросната променлива, било то уникално име поради префикса или чрез ключовата дума this.

Така че, да, мисля, че префиксите все още са полезни. Аз, например, бих предпочел да напиша '_' за достъп до член, а не 'this->'.

person Kent Boogaart    schedule 04.08.2009
comment
компилаторът може да го разреши така или иначе... локалните променливи ще скрият тези в по-висок обхват в повечето езици. Това е за (съмнителна) полза за хората, които четат кода. Всяка прилична IDE ще подчертае локални/членове/глобални по различни начини, така че няма нужда от този вид неща - person rmeador; 04.08.2009
comment
Точно. Местните ще скрият членовете на класа. Помислете за конструктор, който задава тези членове. Обикновено има смисъл да именувате параметрите по същия начин като членовете. - person Kent Boogaart; 04.08.2009
comment
Точно защо използвам 'm_'. Не харесвам местни жители със същото име като моите членове vars. - person Ed S.; 04.08.2009
comment
Просто не създавам локални имена със същите имена като променливите на членовете на първо място. Ако съществуват, това е доста добър намек, че вашият код трябва да бъде преработен. - person jalf; 04.08.2009
comment
Защо това е кодова миризма? Бих казал, че е напълно обичайно и разумно, особено когато става въпрос за конструктори. - person Kent Boogaart; 04.08.2009
comment
@jalf: Това изобщо не е вярно. Какво ще кажете за клас, който има свойство Name? В конструктора искам тази информация, така че вземам параметър, наречен... име! О, чакай, моята членска променлива, която подкрепя Името, се нарича име. Защо това се нуждае от рефакторинг? - person Ed S.; 04.08.2009
comment
Конструкторът трябва (като цяло) да зададе локални в своя списък за инициализация. И там параметрите не засенчват имената на полетата, но и двете са достъпни - така че можете да напишете struct Foo { int x; Foo(int x) : x(x) { ... } }; - person Pavel Minaev; 04.08.2009
comment
Предполагам, че проблемът с това идва, когато правите Foo(int x, bool blee) : x(x) { if (blee) x += bleecount; } // oops, forgot this-> Предпочитам да наричам моите членски променливи нещо полезно и след това давам съкратени имена на параметри на конструктора, които им съответстват: Foo(int f) : foo(f) {...} - person Steve Jessop; 04.08.2009
comment
@Pavel: Конструкторите трябва да го правят, но не винаги могат. Например може да няма конструктор за копиране в типа, който използвате и трябва да копирате на ръка в тялото на вашия конструктор. - person mmmmmmmm; 04.08.2009

Други езици ще използват конвенции за кодиране, те просто са склонни да бъдат различни. C# например вероятно има два различни стила, които хората са склонни да използват, или един от методите на C++ (_variable, mVariable или друг префикс като унгарска нотация), или това, което наричам метод StyleCop.

private int privateMember;
public int PublicMember;

public int Function(int parameter)
{
  // StyleCop enforces using this. for class members.
  this.privateMember = parameter;
}

В крайна сметка става това, което хората знаят и което изглежда най-добре. Аз лично смятам, че кодът е по-четим без унгарска нотация, но може да стане по-лесно да се намери променлива с intellisense, например, ако е прикачена унгарската нотация.

В моя пример по-горе не се нуждаете от префикс m за членски променливи, защото префиксирането на вашата употреба с това. показва същото нещо в наложен от компилатор метод.

Това не означава непременно, че другите методи са лоши, хората се придържат към това, което работи.

person Will Eddins    schedule 04.08.2009

Когато имате голям метод или кодови блокове, е удобно да знаете веднага дали използвате локална променлива или член. това е за избягване на грешки и за по-добра яснота!

person Matthieu    schedule 04.08.2009
comment
Ако имате голям метод, разбийте го за по-голяма яснота. - person sbi; 04.08.2009
comment
Има много причини да не разбиваме някои големи методи. Например, ако вашият метод трябва да поддържа много локално състояние, трябва или да предадете много параметри във вашите подчинени методи, да създадете нови класове, които съществуват единствено с цел предаване на данни между тези методи, или да декларирате данните за състоянието като членски данни на родителския клас. Всички те имат проблеми, които биха повлияли на яснотата или поддържаемостта на метода, в сравнение с единичен дълъг метод (особено този, чиято логика е проста). - person Steve Broberg; 04.08.2009
comment
@sbi: Насоките са точно това; насоки, а не правила. Понякога имате нужда от големи методи, които логично не се поддават на разделяне, а понякога имената на параметрите се сблъскват с членове. - person Ed S.; 04.08.2009
comment
Моля, не правете вашите членски променливи публични. Просто използвайте аксесоари. Скобите трябва да кажат на читателя, че това е променлива член. - person jkeys; 05.08.2009
comment
Имайте предвид, че има предупреждение в gcc (›= 4.6) за откриване на конфликт на имена: -Wshadow - person Caduchon; 21.09.2017

IMO, това е лично. Изобщо не слагам префикси. Както и да е, ако кодът е предназначен да бъде публичен, мисля, че е по-добре да има някои префикси, така че да може да бъде по-четим.

Често големите компании използват свои собствени така наречени „правила за разработчици“.
Btw , най-забавният, но и най-умният, който съм гледал, беше DRY KISS (Не повтаряйте себе си. Бъдете прости, глупако). :-)

person Andrejs Cainikovs    schedule 04.08.2009

Както други вече казаха, важното е да бъдете разговорни (адаптирайте стиловете и конвенциите за именуване към кодовата база, в която пишете) и да сте последователни.

В продължение на години работих върху голяма кодова база, която използва както конвенцията "this->", така и използване на нотация за долна черта postfix за членски променливи. През годините съм работил и върху по-малки проекти, някои от които нямаха никаква конвенция за именуване на членски променливи, а други имаха различни конвенции за именуване на членски променливи. От тези по-малки проекти последователно намирам тези, в които липсва всякаква конвенция, за най-трудни за бързо преминаване и разбиране.

Аз съм много анален за наименуване. Ще агонизирам името да бъде приписано на клас или променлива до такава степен, че ако не мога да измисля нещо, което смятам за „добро“, ще избера да го нарека нещо безсмислено и ще дам коментар, описващ какво всъщност е е. По този начин поне името означава точно това, което възнамерявам да означава - нищо повече и нищо по-малко. И често, след като го използвам известно време, откривам какво трябва да наистина е името и мога да се върна и да модифицирам или преработя по подходящ начин.

Една последна точка по темата за IDE, която върши работата - всичко това е хубаво и хубаво, но IDE често не са налични в среди, където трябва да изпълнявам най-спешната работа. Понякога единственото налично нещо в този момент е копие на „vi“. Също така, виждал съм много случаи, в които довършването на IDE код е разпространило глупост, като например неправилно изписване на имена. Затова предпочитам да не разчитам на IDE патерица.

person Chris Cleeland    schedule 04.08.2009

Първоначалната идея за префикси на членски променливи на C++ беше да се съхранява допълнителна информация за типа, за която компилаторът не знаеше. Така например можете да имате низ с фиксирана дължина от символи и друг, който е променлив и завършва с '\0'. За компилатора и двете са char *, но ако се опитате да копирате от единия на другия, ще имате огромни проблеми. И така, от върха на главата ми,

char *aszFred = "Hi I'm a null-terminated string";
char *arrWilma = {'O', 'o', 'p', 's'};

където "asz" означава, че тази променлива е "ascii низ (завършващ с нула), а "arr" означава, че тази променлива е масив от знаци.

Тогава се случва магията. Компилаторът ще бъде напълно доволен от това твърдение:

strcpy(arrWilma, aszFred);

Но вие, като човек, можете да го погледнете и да кажете „хей, тези променливи всъщност не са от същия тип, не мога да направя това“.

За съжаление на много места се използват стандарти като "m_" за членски променливи, "i" за цели числа, без значение как се използват, "cp" за char указатели. С други думи, те дублират това, което компилаторът знае, и в същото време правят кода труден за четене. Вярвам, че тази пагубна практика трябва да бъде забранена със закон и да подлежи на сурови наказания.

И накрая, има две точки, които трябва да спомена:

  • Разумното използване на функциите на C++ позволява на компилатора да знае информацията, която трябваше да кодирате в необработени променливи в стил C. Можете да създавате класове, които ще позволяват само валидни операции. Това трябва да се направи толкова, колкото е практично.
  • Ако вашите кодови блокове са толкова дълги, че забравяте какъв тип е дадена променлива, преди да я използвате, те са много твърде дълги. Не използвайте имена, реорганизирайте.
person A. L. Flanagan    schedule 04.08.2009
comment
Префиксите, които указват тип или тип променлива, също са нещо, което си струва да се обсъди, но имах предвид главно префикси, указващи дали нещо е (личен) член/поле. Обратната унгарска нотация, която споменавате, може да бъде доста удобна, когато се прилага интелигентно (както във вашия пример). Любимият ми пример, когато има смисъл, са относителните и абсолютните координати. когато видите absX = relX, можете ясно да видите, че нещо може да не е наред. Можете също така да наименувате функциите съответно: absX = absFromRel(relX, отместване); - person VoidPointer; 05.08.2009
comment
Забележка: инициализирането на aszFred е съмнително (предлага неконстантен достъп до литерален низ), а инициализирането на arrWilma дори няма да се компилира. (Вероятно сте възнамерявали да декларирате arrWilma като масив, вместо указател!) Няма проблем обаче, тъй като написахте, че това е просто на върха на главата ви... :-) - person Niels Dekker; 07.08.2009
comment
Упс, напълно си прав. Деца, не опитвайте това у дома. Направете следното: 'const char *aszFred = Здравейте, аз съм низ с нула; char arrWilma[] = {'O', 'o', 'p', 's'};' - person A. L. Flanagan; 01.01.2010

Нашият проект винаги е използвал "its" като префикс за членски данни и "the" като префикс за параметри, без префикс за локални. Малко е сладък, но беше приет от ранните разработчици на нашата система, защото те го видяха използван като конвенция от някои търговски библиотеки с изходни източници, които използвахме по това време (или XVT, или RogueWave - може би и двете). Така че ще получите нещо подобно:

void
MyClass::SetName(const RWCString &theName)
{
   itsName = theName;
}

Голямата причина, която виждам за префиксите за обхват (и никакви други - мразя унгарската нотация) е, че ви предпазва от изпадане в проблеми, като пишете код, където мислите, че се позовавате на една променлива, но всъщност се позовавате на друга променлива със същото име, дефинирано в локалния обхват. Той също така избягва проблема с измислянето на имена на променливи, които да представят същата концепция, но с различни обхвати, като примера по-горе. В такъв случай така или иначе ще трябва да измислите някакъв префикс или различно име за параметъра "theName" - защо не създадете последователно правило, което да се прилага навсякъде.

Просто използването на this-> всъщност не е достатъчно добро - ние не сме толкова заинтересовани от намаляване на двусмислието, колкото от намаляване на грешките в кодирането, а маскирането на имена с идентификатори с локален обхват може да бъде болка. Разбира се, някои компилатори може да имат опцията да извеждат предупреждения за случаи, когато сте маскирали името в по-голям обхват, но тези предупреждения може да се превърнат в неудобство, ако работите с голям набор от библиотеки на трети страни, които са избрали имена за неизползвани променливи, които понякога се сблъскват с вашите собствени.

Що се отнася до самото it/the - честно казано намирам, че е по-лесно за писане от долни черти (като пишещ с докосване, избягвам долни черти, когато е възможно - твърде много разтягане от началните редове) и намирам, че е по-четливо от мистериозно долно черта.

person Steve Broberg    schedule 04.08.2009
comment
Това е най-интуитивното решение с най-бързата крива на обучение, което съм чувал. Иска ми се говоримите езици да са по-гъвкави, за да се справят с всички тези, така че да не се налага да мислим за измислянето на нови техники за разрешаване на неясноти в кода. - person Guney Ozsan; 05.06.2016

Използвам го, защото Intellisense на VC++ не може да каже кога да покаже частни членове при достъп извън класа. Единствената индикация е малък символ "заключване" върху иконата на полето в списъка Intellisense. Това просто улеснява идентифицирането на частни членове (полета). Също така навик от C#, за да бъда честен.

class Person {
   std::string m_Name;
public:
   std::string Name() { return m_Name; }
   void SetName(std::string name) { m_Name = name; }
};

int main() {
  Person *p = new Person();
  p->Name(); // valid
  p->m_Name; // invalid, compiler throws error. but intellisense doesn't know this..
  return 1;
}
person Zack    schedule 04.08.2009

Мисля, че ако имате нужда от префикси, за да разграничите членовете на класа от параметрите на членската функция и локалните променливи, или функцията е твърде голяма, или променливите са с лошо име. Ако не се побира на екрана, за да можете лесно да видите какво е какво, преработете.

Като се има предвид, че те често се декларират далеч от мястото, където се използват, намирам, че конвенциите за именуване на глобални константи (и глобални променливи, въпреки че IMO рядко има нужда да се използват такива) имат смисъл. Но иначе не виждам особена нужда.

Това означава, че използвах долна черта в края на всички частни членове на класа. Тъй като всичките ми данни са лични, това означава, че членовете имат долна черта в края. Обикновено вече не правя това в нови кодови бази, но тъй като като програмист работите предимно със стар код, все още правя това често. Не съм сигурен дали толерантността ми към този навик идва от факта, че правех това винаги и все още го правя редовно, или наистина има повече смисъл от маркирането на променливи членове.

person sbi    schedule 04.08.2009
comment
Това до голяма степен отразява моето усещане по този въпрос. Кодът трябва да може да се чете, без да се прибягва до префикси. Може би не виждаме толкова много употреба на префикс в по-модерните езици, защото техните потребителски общности са прегърнали четливостта малко повече от това, което понякога виждате в C++. Разбира се, C++ може и трябва да бъде четим. Просто през годините е писано много нечетлив C++. - person VoidPointer; 04.08.2009

В Python водещите двойни долни черти се използват за емулиране на частни членове. За повече подробности вижте този отговор

person Konstantin Tenzin    schedule 16.11.2009

Полезно е да се прави разлика между променливи членове и локални променливи поради управлението на паметта. Най-общо казано, променливите на членове, разпределени в купчина, трябва да бъдат унищожени в деструктора, докато локалните променливи, разпределени в купчина, трябва да бъдат унищожени в рамките на този обхват. Прилагането на конвенция за именуване към членски променливи улеснява правилното управление на паметта.

person frankster    schedule 04.08.2009
comment
как така? Деструкторът няма достъп до локални променливи, декларирани в други функции, така че няма място за объркване. Освен това разпределените локални променливи не трябва да съществуват. И променливите членове, разпределени в купчина, трябва да съществуват само в рамките на RAII класове, до голяма степен. - person jalf; 04.08.2009
comment
локалните променливи, разпределени в купчина, не трябва да съществуват, е малко силно. Но ако/когато ги използвате, изключително важно е да се уверите, че те се освобождават правилно, така че дисциплинираната конвенция за именуване за членове спрямо локални променливи помага неизмеримо за осигуряването на това. - person frankster; 04.08.2009

Code Complete препоръчва m_varname за членски променливи.

Въпреки че никога не съм смятал нотацията m_ за полезна, бих дал тежест на мнението на Макконъл при изграждането на стандарт.

person Paul Nathan    schedule 04.08.2009
comment
Не, освен ако не обясни защо долната черта. Аз съм голям фен на неговата книга Rapid Development, която съм препоръчвал тук много пъти, но много по-малко на Code Complete (която, признавам, не съм чел, откакто излезе за първи път). - person ; 04.08.2009

Почти никога не използвам префикси пред имената на моите променливи. Ако използвате достатъчно прилична IDE, трябва да можете да преработвате и лесно да намирате препратки. Използвам много ясни имена и не се страхувам от дълги имена на променливи. Никога не съм имал проблеми с обхвата и с тази философия.

Единственият път, когато използвам префикс, ще бъде на реда за подпис. Ще добавя параметри към метод с _, за да мога да програмирам защитно около тях.

person James    schedule 04.08.2009

Никога не трябва да имате нужда от такъв префикс. Ако такъв префикс ви предлага някакво предимство, вашият стил на кодиране като цяло се нуждае от коригиране и не префиксът пречи на кода ви да бъде ясен. Типичните лоши имена на променливи включват "други" или "2". Вие не коригирате това с изискването да бъде mOther, вие го коригирате, като накарате разработчика да помисли какво прави тази променлива там в контекста на тази функция. Може би е имал предвид remoteSide, или newValue, или secondTestListener, или нещо в този обхват.

Това е ефективен анахронизъм, който все още се разпространява твърде далеч. Спрете да поставяте префикси на вашите променливи и им дайте правилни имена, чиято яснота отразява колко дълго се използват. До 5 реда можете да го наречете "i" без объркване; над 50 реда се нуждаете от доста дълго име.

person dascandy    schedule 05.12.2013

Харесвам имената на променливите да придават само значение на стойностите, които съдържат, и да оставя начина, по който се декларират/имплементират извън името. Искам да знам какво означава стойността, точка. Може би съм направил повече от средното количество рефакторинг, но намирам, че вграждането на начина, по който нещо е имплементирано в името, прави рефакторингът по-досаден, отколкото трябва. Префиксите, указващи къде или как са декларирани членовете на обекта, са специфични за изпълнението.

color = Red;

През повечето време не ме интересува дали Red е enum, структура или нещо друго и ако функцията е толкова голяма, че не мога да си спомня дали color е деклариран локално или е член, вероятно е време да прекъсна функцията на по-малки логически единици.

Ако вашата цикломатична сложност е толкова голяма, че не можете да следите какво се случва в кода без специфични за изпълнението улики, вградени в имената на нещата, най-вероятно трябва да намалите сложността на вашата функция/метод.

Най-често използвам само „това“ в конструктори и инициализатори.

person ChrisG65    schedule 25.09.2015

Използвам m_ за членски променливи само за да се възползвам от Intellisense и свързаната IDE функционалност. Когато кодирам имплементацията на клас, мога да напиша m_ и да видя комбинирания списък с всички m_ членове, групирани заедно.

Но бих могъл да живея без m_ без проблем, разбира се. Просто това е моят стил на работа.

person Hernán    schedule 30.04.2017
comment
Можете също да въведете this-> - person Toast; 18.04.2019

Според JOINT STRIKE FIGHTER AIR VEHICLE C++ CODING STANDARDS (декември 2005 г.):

AV правило 67

Публичните и защитените данни трябва да се използват само в структури, а не в класове. Обосновка: Класът е в състояние да поддържа своя инвариант, като контролира достъпа до своите данни. Класът обаче не може да контролира достъпа до своите членове, ако тези членове не са лични. Следователно всички данни в даден клас трябва да са лични.

Така префиксът m става безполезен, тъй като всички данни трябва да са частни.

Но е добър навик да използвате префикса p преди указател, тъй като това е опасна променлива.

person Pierre-Louis Deschamps    schedule 05.04.2018

Много от тези конвенции са от време без сложни редактори. Бих препоръчал да използвате подходяща IDE, която ви позволява да оцветявате всеки вид променлива. Цветът е много по-лесен за забелязване от всеки префикс.

Ако трябва да получите още повече подробности за променлива, всяка съвременна IDE трябва да може да ви я покаже, като преместите каретката или курсора върху нея. И ако използвате променлива по грешен начин (например указател с . оператор), така или иначе ще получите грешка.

person Elias Mueller    schedule 24.08.2019