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

Проблема с зависимостью. Установите новую версию werkzeug.

https://github.com/odoo/odoo/issues/10184

pip install werkzeug==0.9.4

Должен сделать трюк.

138
задан VoidPointer 4 August 2009 в 04:25
поделиться

24 ответа

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

_Foo

_L

- все зарезервированные слова, а

_foo

_l

- нет. Бывают и другие ситуации, когда перед строчными буквами не допускается использование начальных подчеркиваний. В моем конкретном случае я обнаружил, что _L был зарезервирован Visual C ++ 2005, и конфликт привел к некоторым неожиданным результатам.

Я сомневаюсь в том, насколько полезно размечать локальные переменные.

Вот пример ссылка о том, какие идентификаторы зарезервированы: Каковы правила использования символа подчеркивания в идентификаторе C ++?

44
ответ дан 4 November 2019 в 09:22
поделиться

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

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

0
ответ дан 4 November 2019 в 09:22
поделиться

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

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

1
ответ дан 4 November 2019 в 09:22
поделиться

Code Complete рекомендует m_varname для переменных-членов.

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

1
ответ дан 4 November 2019 в 09:22
поделиться

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

1
ответ дан 4 November 2019 в 09:22
поделиться

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

Учитывая, что они часто объявляются далеко от того места, где они используются, я считаю, что соглашения об именах для глобальных констант (и глобальных переменных, хотя в IMO редко когда возникает необходимость их использовать) имеют смысл. Но в остальном особой необходимости не вижу.

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

2
ответ дан 4 November 2019 в 09:22
поделиться

Я использую его, потому что 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;
}
2
ответ дан 4 November 2019 в 09:22
поделиться

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

char * aszFred = "Привет, я строка с завершающим нулем";
char * arrWilma = {'O', 'o', 'p', 's'};

где «asz» означает, что эта переменная является «строкой ascii (с нулевым символом в конце), а« arr »означает, что эта переменная является символьным массивом.

Затем происходит волшебство. Компилятор будет полностью доволен этим утверждением:

strcpy (arrWilma, aszFred);

Но вы, как человек, можете посмотреть на это и сказать: «Эй, эти переменные на самом деле не одного типа, я не могу этого сделать».

К сожалению, во многих местах используются стандарты, такие как «m_ «для переменных-членов», «i» для целых чисел независимо от того, как они используются, «cp» для указателей на символы. Другими словами, они дублируют то, что знает компилятор, и в то же время затрудняют чтение кода. Я считаю, что эта пагубная практика должна быть запрещена законом и подлежит суровому наказанию.

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

  • Разумное использование функций C ++ позволяет компилятору знать информацию, которую вы должны были кодировать в необработанном C -стилевые переменные. Вы можете создавать классы, которые будут разрешать только допустимые операции. Это должно быть сделано по возможности.
  • Если ваши блоки кода настолько длинные, что вы забываете, какого типа переменная, прежде чем использовать ее, они слишком длинные . Не используйте имена, реорганизуйте.
3
ответ дан 4 November 2019 в 09:22
поделиться

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

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

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

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

3
ответ дан 4 November 2019 в 09:22
поделиться

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

В течение многих лет я работали над большой кодовой базой, которая использует как соглашение «this->», так и нотацию подчеркивания постфикса для переменных-членов. На протяжении многих лет я также работал над небольшими проектами, некоторые из которых не имели какого-либо соглашения для именования переменных-членов, а другие имели разные соглашения для именования переменных-членов. Из этих небольших проектов я постоянно обнаруживал, что те, в которых отсутствуют какие-либо соглашения, являются наиболее сложными для быстрого перехода и понимания.

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

И последнее замечание по теме IDE, выполняющей работу. - все это хорошо и хорошо, но IDE часто недоступны в средах, в которых я выполнял самую неотложную работу. Иногда единственное, что доступно в этот момент, - это копия vi. Как и я' Мы видели много случаев, когда автозавершение кода IDE приводило к такой глупости, как неправильное написание имен. Таким образом, я предпочитаю не полагаться на костыль IDE.

3
ответ дан 4 November 2019 в 09:22
поделиться

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

3
ответ дан 4 November 2019 в 09:22
поделиться

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

Это не

4
ответ дан 4 November 2019 в 09:22
поделиться

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

Обычно это , потому что нет префикса . Компилятору требуется достаточно информации для разрешения рассматриваемой переменной, будь то уникальное имя из-за префикса или через ключевое слово this .

Итак, да, я думаю, что префиксы все еще полезны. Я, например, предпочел бы набрать '_' для доступа к члену, а не 'this ->'.

5
ответ дан 4 November 2019 в 09:22
поделиться

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

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

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

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

6
ответ дан 4 November 2019 в 09:22
поделиться

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

5
ответ дан 4 November 2019 в 09:22
поделиться

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

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

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

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

Я использую их для различения двух . Также, когда я оборачиваю вызовы, например, из Windows Dll, RecvPacket (...) из Dll может быть заключен в RecvPacket (...) в моем коде. В этих конкретных случаях использование префикса типа «_» может сделать их похожими друг на друга, легко определить, что есть что, но по-разному для компилятора

6
ответ дан 4 November 2019 в 09:22
поделиться

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

Учтите:

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 () или каким-то образом украсить переменную-член.

7
ответ дан 4 November 2019 в 09:22
поделиться

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

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

3
ответ дан 4 November 2019 в 09:22
поделиться

Я не могу сказать, насколько он распространен, но, говоря лично, я всегда (и всегда) ставил перед своими переменными-членами префикс 'm'. Например:

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

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

10
ответ дан 4 November 2019 в 09:22
поделиться

Я предпочитаю постфиксные символы подчеркивания, например:

class Foo
{
   private:
      int bar_;

   public:
      int bar() { return bar_; }
};
32
ответ дан 4 November 2019 в 09:22
поделиться

Обычно я не использую префикс для переменных-членов.

Раньше я использовал префикс m , пока кто-то не указал, что «C ++ уже имеет стандарт префикс для доступа к членам: this -> .

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

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

Конечно, очевидным противодействием этому является «да, но тогда вы не можете сразу увидеть, является ли переменная членом класса или нет».

На что я сказать "ну и что?" Если вам нужно это знать, возможно, у вашего класса слишком много состояния.

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

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

108
ответ дан 4 November 2019 в 09:22
поделиться

Если stdint.h недоступен для вашей системы, создайте свой собственный. У меня всегда есть файл с именем "types.h", в котором есть определения типов для всех 8-, 16- и 32-битных значений со знаком / без знака.

и это очень удобный подход экономии времени и уменьшения количества ошибок .

Я использую:

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

Где я хочу сделать тип clear, я использую стандартные суффиксы (например, List, ComboBox и т. д.)

Это позволяет программисту знать об использовании переменной всякий раз, когда они ее видят / используют. Возможно, наиболее важным случаем является "p" для указателя (поскольку использование меняется с var. На var->, и вы должны быть намного осторожнее с указателями - NULL, арифметика указателей и т. Д.), Но все остальные очень удобны.

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

221
ответ дан 4 November 2019 в 09:22
поделиться

В последнее время я склонен предпочитать префикс m_ вместо того, чтобы вообще не иметь префикса, причины не столько в том, что важно отмечать переменные-члены, а в том, что это позволяет избежать двусмысленности, скажете вы иметь код вроде:

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

По этой причине не работает, разрешен только один foo . Итак, ваши варианты:

  • this-> foo = foo;

    Мне это не нравится, так как это вызывает затенение параметров, вы больше не можете использовать предупреждения g ++ -Wshadow , они также длиннее набрать затем m_ . Вы также все еще сталкиваетесь с конфликтами имен между переменными и функциями, когда у вас есть int foo; и int foo (); .

  • foo = foo _; или foo = arg_foo;

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

  • m_foo = foo;

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

  • foo_ = foo;

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

19
ответ дан 4 November 2019 в 09:22
поделиться

В Python передние двойные подчеркивания используются для имитации закрытых членов. Для получения более подробной информации см. этот ответ

2
ответ дан 4 November 2019 в 09:22
поделиться