Зачем использовать префиксы для переменных-членов в классах C ++

Во многих кодах C ++ используются синтаксические соглашения для разметки переменных-членов. Общие примеры включают

  • m_ memberName для публичных членов (где публичные члены используются вообще)
  • _ memberName для частных участников или всех участников

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

По моему опыту, большинство крупных кодовых баз не могут последовательно применять такие правила.

В других языках эти условности гораздо менее распространены. Я лишь изредка вижу это в коде Java или C #. Думаю, я никогда не видел этого в коде Ruby или Python. Таким образом, похоже, что в более современных языках существует тенденция не использовать специальную разметку для переменных-членов.

Это соглашение все еще полезно сегодня в C ++ или это просто анахронизм. Тем более, что он так непоследовательно используется в библиотеках. Разве другие языки не показали, что можно обойтись без префиксов членов?


person VoidPointer    schedule 04.08.2009    source источник
comment
Я предпочитаю это; в сложных кодовых базах может быть важно знать, какие вары являются локальными, а какие нет. Я обычно использую префикс вместо того, чтобы заставить это- ›что, как я считаю, требует большого количества дополнительных операций ввода и является необязательным (тогда как именование заставит вас это сделать)   -  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)


Будьте осторожны с использованием символа подчеркивания в начале. Ведущее подчеркивание перед заглавной буквой в слове зарезервировано. Например:

_Foo

_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 ++ являются указателями общего соглашения на массивы char с завершающим нулем, и на самом деле это не так уж сложно чтобы знать, что «customerName» - это строка!

Тем не менее, я использую префиксы для указания использования переменной (по сути, «Венгерские приложения», хотя я предпочитаю избегать термина венгерский, поскольку он имеет плохую и несправедливую связь с Венгерской системой), и это очень удобный подход, экономящий время и сокращающий количество ошибок.

Я использую:

  • м для членов
  • c для констант / только для чтения
  • p для указателя (и pp для указателя на указатель)
  • v для летучих
  • s для статического
  • i для индексов и итераторов
  • е для мероприятий

Если я хочу сделать тип ясным, я использую стандартные суффиксы (например, 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' также позволяет избежать (ИМХО) уродливой и многословной нотации "this->" и несогласованности, которую она гарантирует (даже если вы будете осторожны, вы обычно получите смесь 'this-> data' и 'data' в том же классе, потому что ничто не требует последовательного написания имени).

Обозначение this предназначено для устранения двусмысленности - но зачем кому-то намеренно писать код, который может быть неоднозначным? Неопределенность рано или поздно приведет к ошибке. А в некоторых языках «this» нельзя использовать для статических членов, поэтому вы должны ввести «особые случаи» в свой стиль кодирования. Я предпочитаю иметь одно простое правило кодирования, которое применяется везде - явное, недвусмысленное и последовательное.

Последнее важное преимущество - это Intellisense и автозаполнение. Попробуйте использовать Intellisense в Windows Form, чтобы найти событие - вам нужно прокрутить сотни загадочных методов базового класса, которые вам никогда не нужно будет вызывать для поиска событий. Но если бы каждое событие имело префикс «e», они автоматически попадали бы в группу под «e». Таким образом, префикс позволяет группировать элементы, константы, события и т. Д. В списке intellisense, что значительно ускоряет и упрощает поиск нужных имен. (Обычно метод может иметь около 20-50 значений (locals, params, members, consts, events), доступных в его области действия. Но после ввода префикса (сейчас я хочу использовать индекс, поэтому я набираю 'i. .. '), мне представлены только 2-5 вариантов автозаполнения. Люди, которые «лишний набор» приписывают префиксы и значимые имена, резко сокращают пространство поиска и заметно ускоряют скорость разработки)

Я ленивый программист, и приведенное выше соглашение экономит мне много работы. Я могу кодировать быстрее и делаю гораздо меньше ошибок, потому что знаю, как следует использовать каждую переменную.


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

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

  • «Схемы префиксов - это плохо / плохо». Я согласен с тем, что "m_lpsz" и ему подобные плохо продуманы и совершенно бесполезны. Вот почему я бы посоветовал использовать хорошо продуманную нотацию, разработанную для поддержки ваших требований, а не копировать что-то, не подходящее для вашего контекста. (Используйте подходящий инструмент для работы).

  • «Если я изменю использование чего-либо, мне придется переименовать это». Да, конечно, да, именно в этом суть рефакторинга и почему в IDE есть инструменты рефакторинга, позволяющие выполнять эту работу быстро и безболезненно. Даже без префиксов изменение использования переменной почти наверняка означает, что ее имя следует изменить.

  • «Префиксы меня просто сбивают с толку». Как и любой другой инструмент, пока вы не научитесь им пользоваться. Как только ваш мозг привыкнет к шаблонам именования, он автоматически отфильтрует информацию, и вы действительно не будете возражать, что префиксы там больше не будут. Но вы должны твердо использовать такую ​​схему в течение недели или двух, прежде чем вы действительно станете "бегло". И тогда многие люди смотрят на старый код и начинают задаваться вопросом, как им вообще удалось справиться без хорошей схемы префиксов.

  • «Я могу просто взглянуть на код, чтобы решить эту проблему». Да, но вам не нужно тратить время на поиск в другом месте кода или запоминание каждой мелочи в нем, когда ответ находится прямо там, где ваш глаз уже сфокусирован.

  • (Некоторая часть) этой информации можно найти, просто дождавшись всплывающей подсказки для моей переменной. да. Там, где это поддерживается, для некоторых типов префиксов, когда ваш код компилируется чисто, после ожидания вы можете прочитать описание и мгновенно найти информацию, которую префикс мог бы передать. Я считаю, что префикс - это более простой, надежный и эффективный подход.

  • "Больше печатать". Действительно? Еще на один персонаж? Или это - с инструментами автозаполнения IDE, это часто сокращает набор текста, потому что каждый символ префикса значительно сужает пространство поиска. Нажмите «e», и в intellisense появятся три события в вашем классе. Нажмите «c», и отобразятся пять констант.

  • "Я могу использовать this-> вместо m". Ну да, можно. Но это просто более уродливая и многословная приставка! Только он несет гораздо больший риск (особенно в командах), потому что для компилятора он необязателен, и поэтому его использование часто непоследовательно. m с другой стороны, является кратким, ясным, явным и необязательным, поэтому при его использовании гораздо сложнее ошибиться.

person Community    schedule 04.08.2009
comment
Я имею в виду, что я прочитал, что проблема с Hungarien Notation возникла только из-за неправильного понимания Симони. Он написал, что префикс должен использоваться для обозначения типа переменной, где он имел в виду тип вроде чего-то, а не буквального типа данных. Позже разработчики платформы из 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 (где нулевое завершение является важным отличием) я согласен с вами . ИМО, любая схема, которую мы используем, должна быть адаптирована по мере необходимости, чтобы наилучшим образом удовлетворить наши собственные потребности - Итак, если нулевое завершение влияет на использование вами переменной, нет ничего плохого в объявлении 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
@ Томас: Все хорошие моменты. Некоторые преимущества сильны, некоторые - слабее. Более сильные случаи для p относятся к множественным косвенным ссылкам (X vs pX vs ppX) и арифметике указателей (X ++ vs pX ++ vs * pX ++), когда знание того, что что-то является указателем, жизненно важно. Для меня другие случаи по-прежнему полезны - компиляция или всплывающая подсказка - это IMO, просто менее эффективные способы определения того, что переменная является указателем (и другие минусы: всплывающие подсказки нельзя скопировать и вставить в примеры за пределами вашей IDE и т. Д.) . - person Jason Williams; 14.11.2012
comment
Проголосовали за четкие, исчерпывающие и интересные объяснения, однако здесь мало что говорит о том, как это экономит время в C ++. YET остается в значительной степени неиспользованным во многих других языках. - 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: В те дни я много занимался рефакторингом кода. Хотел бы я больше пользоваться авто. И не только для того, чтобы меньше печатать. Авто заставляет вас не связывать себя каким-либо типом. Это действительно помогает в долгосрочной перспективе. ИМХО конечно. И незнание, с каким типом вы работаете, не проблема, на самом деле это хорошая функция. - 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 # константа или статика подразумевают, что это член, поэтому я просто использую '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: Как ты думаешь, почему статика - это плохо? - person Oleksa; 26.06.2020
comment
@ Джейсон Уильямс: Что вы используете для массива C? mArray, pArray или что-то еще? - person antho; 22.10.2020
comment
@antho: Я обычно использую суффикс для списков (любой формы, то есть массивов, коллекций списков, связанных списков - поэтому массив транспортных средств будет списком транспортных средств). Любой префикс должен разъяснять использование массива (m для члена и т. Д.). Подумайте: предоставление каждой строки префикса ap только потому, что это технически указатель на массив char, обычно не добавляет значения (нам обычно не нужно использовать строки в качестве массивов), поэтому я обычно не буду использовать префикс, но если Я использовал указатель на символ для перехода по символам в строке, я бы обязательно использовал префикс ap, чтобы прояснить это. - person Jason Williams; 26.10.2020
comment
Хорошо, спасибо, комбинация суфикса и префикса может быть хорошей. Спасибо за совет - person antho; 26.10.2020
comment
Мне вообще не нравится этот стиль кодирования. Все суффиксы субъективны и могут относиться к любому типу переменной в зависимости от кодировщика (как вы только что продемонстрировали), в то время как простое использование этого - ›ясно и недвусмысленно. Не говоря уже о том, что этот суффиксный стиль просто вносит шум в кодовые базы, которые предпочитают использование 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 ++ также не используют префиксы в своих примерах: 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 других варианта, например (а) используйте полные имена, такие как foo, только для членов и вместо этого используйте однобуквенные или короткие имена для параметров или других локальных / одноразовых имен, таких как int f; или (б) префикс параметров или других локальных переменных. Хорошая точка зрения на 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
@ Нил, я с тобой. @mgb: Ненавижу имена, начинающиеся с '_'. Это просто приглашение к тому, что что-то пойдет не так в будущем. - person Martin York; 04.08.2009
comment
@Neil: Какое соглашение вы тогда используете, если вы не используете подчеркивания и не используете верблюжий регистр? - 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
В моем случае с верблюдами был DepositBankAccount. Или я запуталась? - person ; 04.08.2009
comment
Ах я вижу. Насколько я знаю, depositBankAccount - это верблюжий регистр, и я думаю, что наиболее распространенное имя для DepositBankAccount - это Pascal-case? (Я никогда не использовал Паскаль, но довольно часто слышал, что это описывается как случай Паскаля.) - person jalf; 05.08.2009
comment
@jalf Я впервые выучил Паскаль в 1980 году, и тогда люди использовали мешанину способов именования вещей. Delphi от Borland (вероятно, единственный оставшийся в живых Pascal) использует стиль DepositBankAccount, но то же самое делает то, что должно быть самой влиятельной технологией из всех - Windows API. - person ; 05.08.2009
comment
@neil: Я точно не знаю и просто подумал, что и depositBankAccount, и DepositBankAccount - верблюжий случай. Давайте посмотрим, что говорит Википедия ... Эй! Говорят то же самое! Но является ли Википедия авторитетным источником для этого? - person mmmmmmmm; 05.08.2009
comment
@rstevens Это авторитетный источник чего-либо? Может ли человек однажды войти в ту же реку? Честно говоря, верблюжий падеж - это термин, который я никогда не набирал перед этой веткой. Я использовал его только потому, что это сделал mgb в своем комментарии. - 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

Основная причина для префикса члена состоит в том, чтобы различать локальную функцию-член и переменную-член с тем же именем. Это полезно, если вы используете геттеры с именем вещи.

Учитывать:

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

Я не думаю, что один синтаксис имеет реальную ценность перед другим. Как вы упомянули, все сводится к единообразию исходных файлов.

Единственный момент, когда мне интересны такие правила, - это когда мне нужны две одинаковые вещи, например:

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, все члены которых равны _2 _ / _ 3_, либо POD structs, все переменные которых равны public (а часто также const). Так что мне никогда не нужно задумываться об уровне доступа какого-либо члена. - person underscore_d; 28.01.2016

Другие пытаются принудительно использовать this-> member всякий раз, когда используется переменная-член

Обычно это из-за отсутствия префикса. Компилятору требуется достаточно информации для разрешения рассматриваемой переменной, будь то уникальное имя из-за префикса или через ключевое слово 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_. Мне не нравятся местные жители с тем же именем, что и мои участники. - person Ed S.; 04.08.2009
comment
Я просто не создаю локальные переменные с теми же именами, что и вары-члены. Если они существуют, это хороший намек на то, что ваш код нужно реорганизовать. - person jalf; 04.08.2009
comment
Почему это запах кода? Я бы сказал, что это совершенно нормально и разумно, особенно когда речь идет о конструкторах. - person Kent Boogaart; 04.08.2009
comment
@jalf: Это совсем не так. Как насчет класса, у которого есть свойство Name? В конструкторе мне нужна эта информация, поэтому я беру параметр с именем ... 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

ИМО, это личное. Приставки вообще не ставлю. В любом случае, если код должен быть общедоступным, я думаю, что он должен иметь несколько префиксов, чтобы он был более читабельным.

Часто крупные компании используют свои собственные так называемые «правила разработчика».
Кстати , самым смешным, но самым умным, что я видел, был DRY KISS (Dont Repeat Yourself. Keep It Simple, Stupid). :-)

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» для указателей на символы. Другими словами, они дублируют то, что знает компилятор, и в то же время затрудняют чтение кода. Я считаю, что эта пагубная практика должна быть запрещена законом и подлежать суровому наказанию.

Наконец, я должен упомянуть два момента:

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

В нашем проекте всегда использовалось «it» в качестве префикса для данных членов и «the» в качестве префикса для параметров, без префикса для локальных пользователей. Это немного забавно, но было принято ранними разработчиками нашей системы, потому что они видели, что это использовалось как соглашение некоторыми коммерческими исходными библиотеками, которые мы использовали в то время (либо XVT, либо RogueWave - возможно, и то, и другое). Так получится что-то вроде этого:

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

Основная причина, по которой я вижу префиксы области видимости (и никакие другие - я ненавижу венгерскую нотацию), заключается в том, что они предотвращают возникновение проблем путем написания кода, в котором вы думаете, что ссылаетесь на одну переменную, но на самом деле вы ссылаетесь на другую переменную. с тем же именем, определенным в локальной области. Это также позволяет избежать проблемы придумывания имен переменных для представления той же концепции, но с разными областями действия, как в примере выше. В этом случае вам все равно придется придумать какой-то префикс или другое имя для параметра theName - почему бы не создать единообразное правило, которое применяется везде.

Простого использования this-> недостаточно - мы не так заинтересованы в уменьшении двусмысленности, как в уменьшении ошибок кодирования, и маскирование имен с помощью идентификаторов с локальной областью видимости может быть проблемой. Конечно, некоторые компиляторы могут иметь возможность выдавать предупреждения для случаев, когда вы замаскировали имя в более крупном масштабе, но эти предупреждения могут стать помехой, если вы работаете с большим набором сторонних библиотек, которые случайно выбрали имена неиспользуемых переменных, которые иногда конфликтуют с вашими собственными.

Что касается самого элемента / 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 перечислением, структурой или чем-то еще, и если функция настолько велика, что я не могу вспомнить, был ли цвет объявлен локально или является членом, вероятно, пора сломать функцию на более мелкие логические единицы.

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

В основном я использую только this в конструкторах и инициализаторах.

person ChrisG65    schedule 25.09.2015

Я использую m_ для переменных-членов, просто чтобы воспользоваться преимуществами Intellisense и связанных с ним функций IDE. Когда я кодирую реализацию класса, я могу набрать m_ и увидеть поле со списком со всеми членами m_, сгруппированными вместе.

Но, конечно, я мог бы жить без м_ без проблем. Это просто мой стиль работы.

person Hernán    schedule 30.04.2017
comment
Вы также можете ввести this-> - person Toast; 18.04.2019

Согласно СТАНДАРТАМ КОДИРОВАНИЯ C ++ для JOINT STRIKE FIGHTER AIR VEHICLE AIR VEHICLE (декабрь 2005 г.):

Правило АВ 67

Открытые и защищенные данные следует использовать только в структурах, а не в классах. Обоснование: класс может поддерживать свой инвариант, контролируя доступ к своим данным. Однако класс не может контролировать доступ к своим членам, если эти члены не являются частными. Следовательно, все данные в классе должны быть приватными.

Таким образом, префикс m становится бесполезным, поскольку все данные должны быть конфиденциальными.

Но это хорошая привычка использовать префикс p перед указателем, поскольку это опасная переменная.

person Pierre-Louis Deschamps    schedule 05.04.2018

Многие из этих соглашений возникли в те времена, когда не было опытных редакторов. Я бы порекомендовал использовать подходящую среду IDE, которая позволяет раскрашивать все типы переменных. Цвет определить намного легче, чем любой префикс.

Если вам нужно получить еще более подробную информацию о переменной, любая современная IDE должна иметь возможность показать ее вам, наведя на нее курсор или курсор. И если вы неправильно используете переменную (например, указатель с оператором.), Вы все равно получите ошибку.

person Elias Mueller    schedule 24.08.2019