Соглашения об именах переменных в C++
-
04-07-2019 - |
Вопрос
Я родом из мира .NET и новичок в написании C++.Мне просто интересно, какие соглашения об именах являются предпочтительными, когда дело доходит до именования локальных переменных и членов структуры.
Например, устаревший код, который я унаследовал, содержит множество таких:
struct MyStruct
{
TCHAR szMyChar[STRING_SIZE];
bool bMyBool;
unsigned long ulMyLong;
void* pMyPointer;
MyObject** ppMyObjects;
}
Имея опыт работы с C#, я был шокирован, увидев переменные с венгерской нотацией (я не мог перестать смеяться над префиксом pp, когда впервые его увидел).
Вместо этого я бы предпочел называть свои переменные именно так (хотя я не уверен, что использование заглавной буквы является хорошим соглашением.Я видел другие способы (см. ссылки ниже)):
struct MyStruct
{
TCHAR MyChar[STRING_SIZE];
bool MyBool;
unsigned long MyLong;
void* MyPointer;
MyObject** MyObjects;
}
Мой вопрос:Является ли этот (первый способ) предпочтительным способом именования переменных в C++?
Использованная литература:
http://geosoft.no/development/cppstyle.html
http://www.syntext.com/books/syntext-cpp-conventions.htm
http://ootips.org/hungarian-notation.html
Спасибо!
Решение
Такая венгерская нотация совершенно бесполезна и, возможно, даже хуже, чем бесполезна, если вам нужно изменить тип чего-либо.(А правильный разновидность венгерской нотации это другая история.)
Я предлагаю вам использовать все, что делает ваша группа.Если вы единственный человек, работающий над программой, назовите их так, как вам удобнее.
Другие советы
Самое главное — быть последовательным.Если вы работаете с устаревшей базой кода, назовите свои переменные и функции. последовательно с соглашением об именах устаревшего кода.Если вы пишете новый код, который взаимодействует только со старым кодом, используйте в новом коде свое соглашение об именах, но будьте последовательны и сами с собой.
Нет.«Неправильная венгерская нотация» — особенно pp для двойной косвенности — имела некоторый смысл для ранних компиляторов C, где можно было написать
int * i = 17;
int j = ***i;
даже без предупреждения компилятора (и это может быть даже правильный код на правильном оборудовании...).
«Истинная венгерская нотация» (по ссылке главного компьютерщика) по-ИМО все еще является допустимым вариантом, но не обязательно предпочтительным.Современное приложение на C++ обычно имеет десятки или сотни типов, для которых вы не найдете подходящих префиксов.
Я до сих пор использую его локально в некоторых случаях, когда мне приходится микшировать, например.целочисленные переменные и переменные с плавающей запятой, которые имеют очень похожие или даже идентичные имена в проблемной области, например.
float fXmin, fXmax, fXpeak; // x values of range and where y=max
int iXmin, iXMax, iXpeak; // respective indices in x axis vector
Однако при поддержке устаревшего кода, который последовательно следует некоторым соглашениям (даже если они в общих чертах), вам следует придерживаться используемых там соглашений - по крайней мере, в существующих модулях/модулях компиляции, которые необходимо поддерживать.
Мои рассуждения:Целью стандартов кодирования является соблюдение принципа наименьшего неожиданности.Последовательное использование одного стиля более важно, чем то, какой стиль вы используете.
Что может не нравиться или высмеивать «ppMyObjects» в этом примере, кроме того, что он несколько уродлив?В любом случае у меня нет твердого мнения, но он дает с первого взгляда полезную информацию, чего нет в «MyObjects».
Я согласен с другими ответами здесь.Либо продолжайте использовать стиль, который вам дали из поколения в поколение ради последовательности, либо придумайте новое соглашение, которое подойдет вашей команде.Важно, чтобы команда была в согласии, так как почти гарантировано, что вы будете изменять одни и те же файлы.Сказав это, некоторые вещи, которые я нашел очень интуитивными в прошлом:
Переменные-члены класса/структуры должны выделяться — я обычно добавляю к ним префикс m_.
Глобальные переменные должны выделяться - обычно префикс g_.
Переменные обычно должны начинаться с нижнего регистра.
Имена функций обычно должны начинаться с верхнего регистра.
Макросы и, возможно, перечисления должны быть в верхнем регистре.
Все имена должны описывать, что делает функция/переменная, и никогда не должны описывать ее тип или значение.
Я сам увлекаюсь венгерской нотацией, потому что считаю, что это придает коду читаемость, и я предпочитаю самодокументируемый код комментариям и поискам.
Тем не менее, я думаю, вы можете обосновать необходимость пожертвовать предпочитаемым вами стилем и некоторой дополнительной простотой обслуживания ради единства команды.Я не верю в аргумент согласованности ради единообразной читаемости кода, особенно если вы снижаете читабельность ради согласованности...это просто не имеет смысла.Однако, ладя с людьми, с которыми вы работаете, возможно, стоит немного больше запутаться в типах, рассматривающих переменные.
Венгерская нотация была распространена среди пользователей API Win32 и MFC.Если ваши предшественники использовали это, вам, вероятно, лучше продолжать использовать это (хотя это отстой).В остальном мире C++ никогда не было этого бессмысленного соглашения, поэтому не используйте его, если вы используете что-то кроме этих API.
Я думаю, что вы по-прежнему обнаружите, что большинство магазинов, программирующих на Visual C++, придерживаются венгерской нотации или, по крайней мере, ее упрощенной версии.В нашем магазине половина нашего приложения представляет собой устаревший C++ с новым блестящим слоем C# сверху (с управляемым слоем C++ посередине). Наш код C++ продолжает использовать венгерскую нотацию, но наш код C# использует нотацию, представленную вами.Я думаю, что это некрасиво, но это последовательно.
Я говорю: используйте для своего проекта все, что хочет ваша команда.Но если вы работаете над устаревшим кодом или присоединяетесь к команде, для обеспечения единообразия придерживайтесь существующего стиля.
Все зависит от личных предпочтений.Я работал в двух компаниях с похожими схемами, где переменные-члены называются m_varName.Я никогда не видел, чтобы венгерская нотация использовалась на работе, и мне она действительно не нравится, но опять же по предпочтениям.Я считаю, что IDE должна позаботиться о том, чтобы сообщить вам, какой это тип, поэтому, пока имя достаточно описывает то, что он делает ( m_color, m_shouldBeRenamed ), тогда это нормально.Еще мне нравится разница между переменной-членом, локальной переменной и именованием констант, поэтому легко увидеть, что происходит в функции и откуда берутся переменные.Член:m_varname const:c_varname local:имя_переменной
Я также предпочитаю CamelCase, и в основном я видел людей, использующих CamelCase на C++.Лично я не использую никаких префиксов, кроме частных/защищенных членов и интерфейсов:
class MyClass : public IMyInterface {
public:
unsigned int PublicMember;
MyClass() : PublicMember(1), _PrivateMember(0), _ProtectedMember(2) {}
unsigned int PrivateMember() {
return _PrivateMember * 1234; // some senseless calculation here
}
protected:
unsigned int _ProtectedMember;
private:
unsigned int _PrivateMember;
};
// ...
MyClass My;
My.PublicMember = 12345678;
Почему я решил опустить префиксы для публичных участников:Потому что к публичным членам можно обращаться напрямую, как в структурах, и они не конфликтуют с частными именами.Вместо использования подчеркивания я также видел, как люди использовали первую строчную букву для обозначения участников.
struct IMyInterface {
virtual void MyVirtualMethod() = 0;
};
Интерфейсы по определению содержат только чисто виртуальные методы, которые необходимо реализовать позже.Однако в большинстве случаев я предпочитаю абстрактные классы, но это уже другая история.
struct IMyInterfaceAsAbstract abstract {
virtual void MyVirtualMethod() = 0;
virtual void MyImplementedMethod() {}
unsigned int EvenAnPublicMember;
};
Видеть Стандартное руководство по высокоинтегральному программированию на C++ для еще большего вдохновения.
Наша команда использует Соглашение о коде Google C++:
Это пример имени переменной:
string table_name; // OK - uses underscore.
string tablename; // OK - all lowercase.
string tableName; // Bad - mixed case.
Если вы используете Camelcase, соглашение состоит в том, чтобы извлечь выгоду из первой буквы для классов структур и не примитивных имен типов, а также в нижней части первой буквы для членов данных.Заглавные буквы методов, как правило, смешанные, мои методы, как правило, являются глаголами и уже различаются скобками, поэтому я не пишу методы с заглавной буквы.
Лично я не люблю читать код Camelcase и предпочитаю подчеркивать нижний чехол для идентификаторов данных и методов, капитализации типов и резервирования прописного заглавного регистра для аббревиатуры и редкого случая, когда я использую макрос (предупреждение, что это макрос).