ПРОГРАММИРОВАНИЕ НА VISUAL C++

Выпуск No. 15 от 18 сентября 2000 г.

Доброе время суток!

Сегодня мы с вами поговорим о такой вещи, как стиль программирования.

/ / / / С++ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 

ЛЕГКО ЧИТАЕМЫЙ КОД  И НАДЕЖНОСТЬ ПРОГРАММ

Если вам когда-нибудь приходилось разбираться в чужой программе, или даже в своей собственной, но написанной несколько лет назад, да еще когда поджимает время, вы скорее всего знаете, какая это неприятная и сложная задача. Порой бывает легче весь код написать заново (а многие так и делают). Конечно, существует поговорка "настоящие программисты не пишут комментарии: если программу было трудно написать, в ней должно быть трудно что-то понять и еще труднее что-либо изменить". О комментариях мы еще поговорим, печально то, что очень многие следуют этому принципу в самой программе. "Неважно", думают они, "как это написано, главное побыстрее проверить, работает ли это вообще". Самые прилежные из них впоследствии переписывают отдельные куски кода, но таких единицы. Большинство же, убедившись в работоспособности алгоритма, оставляют все как есть и переходят к новым задачам.
Как показывает многолетняя практика, это большая ошибка. Усилия, потраченные на "причесывание" кода, окупаются с лихвой. Но по-настоящему ценится умение писать сразу такой код, который не нуждается в причесывании. Это умение не приходит само по себе, а вырабатывается постепенно, в нем надо постоянно практиковаться. И когда вы говорите себе "а, это ведь просто небольшая утилитка для удобства, вот когда получу настоящий заказ - буду писать красиво", вы тем самым приучаете себя к неправильному стилю написания программ.

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

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

1. Обязательно соблюдайте отступы. Хотя Visual C++ и делает отступы автоматически, иногда они все же нарушаются. С их помощью сразу видна структура программы.
Кстати, многие знают, что для того, чтобы подвинуть блок текста вправо, нужно выделить его и нажать Tab, но почему-то даже не догадываются, что если нажать Shift-Tab, текст сдвинется влево! Попробуйте, это очень удобно. Лучше вместо символа табуляции использовать пробелы (Tools|Options|Tabs|Insert Spaces). Тогда ваши программы в любом редакторе будут с корректными отступами.

2. Про комментарии в коде я ничего говорить не буду... ну, почти ничего. Все, что можно было сказать, уже сказано до меня. Все равно лень людям их писать. Одно только вам посоветую: если уж сильно неохота сочинять комментарии 50/50 с кодом - все-таки постарайтесь самые ключевые и/или неочевидные моменты отмечать.
И запомните: неряшливый и запутанный код нужно не комментировать, а переписывать!

3. Именованные константы пишите в верхнем регистре, чтобы можно было мгновенно отличить их от переменных. Например, MAX_ELEMENTS и BORDER_WIDTH, а не Max_Elements и border_width.

4. Имена переменных начинайте с маленькой буквы, названия типов - с заглавной.

5. Глобальные переменные по написанию должны отличаться от обычных. Как правило, для этого используют префикс "g_": g_RefCount, g_BaseDir. Вообще, их количество следует минимизировать. Статические переменные можно обозначать суффиксом "s_", члены классов- "m_".

6. Переменным, имеющим длительный период существования, следует давать длинные имена. Локальным и временным переменным можно давать имена покороче.

7. Помните, что объект всегда подразумевается, т.е. не нужно повторять имя объекта в его методе. Например, MyObject->GetObjectColor() - эту функцию следует назвать просто GetColor().

8. Вкладывайте смысл в имена функций. Используйте слово "find" когда где-то что-то ищется, "get" когда что-то хотите получить, "set"- установить. "Initialize" или "init" - инициализация, "compute" - вычисление, "open/close" - открытие/закрытие, и т.д.  Также в паре следует использовать следующие имена: add/remove, create/destroy, start/stop, insert/delete, increment/decrement, old/new, begin/end, first/last, up/down, min/max, next/previous, old/new, open/close, show/hide. Т.е. если вы одну функцию назвали AddTitle(), то противоположную по действию надо назвать не DestroyTitle() или DeleteTitle(), а RemoveTitle().

9. Перед именами переменных, представляющих количество чего-то, ставьте префикс "n": nColors, nItems. Переменные, обозначающие порядковый номер чего-то, дополняйте суффиком "No": RecordNo, LineNo.

10. Не злоупотребляйте сокращениями. Согласитесь, что, например, смысл GetListAverage() гораздо легче понять, чем GetLstAvg() (ведь это, в принципе, может обозначать и GetLastAvenger() ;-).

11. Избегайте логических переменных, обозначающих отрицание. Found, а не notFound; Good, а не notGood. Вообще, хорошим стилем считается дополнять логические переменные префиксом "is": isFound, isGood. Это же относится к функциям, возвращающим значение true/false, напр. IsKindOf().

12. Константы из типов-перечислений (enum) должны содержать имя типа. COLOR_BLUE, а не BLUE; FILE_ERROR_ALREADY_EXISTS, а не ALREADY_EXISTS.

13. Всегда приводите типы к нужным явно, не полагаясь на автоматику.

14. Переменные, связанные между собой по смыслу, можно объявлять одной строкой:
int x,y,z; 
Record first,last, next, previous;
Никак не связанные переменные лучше объявлять на разных строках, даже если они одного типа.

15. В пустых циклах хорошо явно прописывать continue. Этим вы показываете, что оставили цикл пустым нарочно, а не по ошибке. Пример: while ( *p++ = *q++ ) continue;

Ну, хватит пожалуй. Если кто-то особенно заинтересовался этим вопросом, он может посмотреть более чем 70 подобных правил в Geosoft's C++ Programming Style Guidelines.
Должен заметить, что далеко не со всеми положениями этого документа я согласен. Например, я не считаю нужным обязательно начинать имена функций с маленькой буквы, - действительно важно различать переменные и типы, а функцию от типа отличить гораздо легче. Или еще, например, правило всем private-членам классов давать суффикс "_" - ну вот не нравится и все тут... Я здесь привел самые, на мой взгляд, нужные и, прошу прощения за тавтологию, "правильные" правила; те, которые встречаются практически во всех документах такого типа.
Так что дам еще один, последний, совет: подходите ко всем правилам, необходимость которых для вас не очевидна, с некоторой толикой здравого смысла.

 / / / ВОПРОС-ОТВЕТ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / 

|Q  Как в VC++ 6.0 можно сделать окно, которое не будет видно на Taskbar'e? - Kirill

|A  Самый простой способ - это создать основное окно с расширеным стилем окна WS_EX_TOOLWINDOW:

hWnd = CreateWindowEx(WS_EX_TOOLWINDOW, szWindowClass, szTitle, < BR >         WS_OVERLAPPEDWINDOW,0,0,100,100,NULL, 0, hInstance, NULL);

При использовании MFC следует перекрыть метод PreCreateWindow ():

BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
  if( !CMDIFrameWnd::PreCreateWindow(cs) ) return FALSE;

  cs.dwExStyle=WS_EX_TOOLWINDOW;

  return TRUE;
}

Но такое решение не всегда приемлемо - у созданного таким образом окна на тайтлбаре может находится только кнопка закрытия, и его заголовок отличается от заголовков других окон (он меньше). Для того, чтобы исправить эти недостатки, сначала создаем невидимое окно со стилем WS_EX_TOOLWINDOW, а затем дочернее окно, которое будет выполнять роль основного окна приложения. Это будет выглядеть следующим образом:

//...
HWND hWnd1,hWnd2;
hInst = hInstance;
hWnd1 = CreateWindowEx(WS_EX_TOOLWINDOW , szWindowClass1, szTitle, 0, 0, 0, 100, 100, NULL, 0, hInstance, NULL); // cоздаем невидимое окно

// создаем окно, которое будет основным; указываем hWnd1 в кач.родителя:
hWnd2 = CreateWindowEx(0, szWindowClass2, szTitle, WS_OVERLAPPEDWINDOW, 0, 0, 100, 100, hWnd1, 0, hInstance, NULL);

ShowWindow(hWnd1, FALSE);    // скрываем 1-ое окно
UpdateWindow(hWnd1);

ShowWindow(hWnd2, nCmdShow); // делаем дочернее окно видимым
UpdateWindow(hWnd2);  

- Bad Sector

|Небольшое дополнение:Если вам нужно убирать кнопку с таскбара только тогда, когда ваше приложение минимизировано (например, чтобы реализовать функцию "минимизировать в системный трей"), то все становится гораздо проще. Достаточно в обработчике OnSysCommand поставить реакцию на минимизацию окна ( т.е. когда параметр nID равен SC_MINIMIZE вызывать ShowWindow(hWnd, SW_HIDE) ). А при получении соответствующего сообщения от иконки в трее, не забывать восстановить окно. (про работу с системным треем см. выпуск No.11)

/ / /  В ПОИСКАХ ИСТИНЫ  / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /

Q|
В Visual C++ 6.0  создаётся ImageList с помощью ImageList_LoadImage. Потом две загруженные картинки рисуются в окошке - сначала одна, потом поверх неё другая (используется маска) - функция ImageList_Draw. Проблема в том, что рисуется только в 16 стандартных цветах. Картинка 24-битная. Пробовал и с 256 и 16-цветными, с использованием палитры - эффект тот же. Если не сложно, подскажи, как её нарисовать в 16M цвете (использую только API, без MFC)? - Дрон

/ / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / / /

Всего вам доброго и не скучайте !

©Алекс Jenter    mailto:jenter@mail.ru
Красноярск, 2000.

Предыдущие выпуски     Статистика рассылки