![picture](/_resources/images/progcat.png) - [К списку документов](Readme.md) # Qt Code Style - Правила кодирования с использованием Qt C++ Ниже представлен обзор соглашений по написанию кода с использованием Qt. При использовании Qt предпочтительно использовать стиль кодирования, который используется в библиотеке, чтобы добиться единообразия кода. ### Содержание - [Кодировка](#кодировка) - [Заголовочные файлы](#заголовочные-файлы) - [Директивы препроцессора](#директивы-препроцессора) - [Отступы](#отступы) - [Объявление переменных, функций и классов](#объявление-переменных-функций-и-классов) - [Пробелы](#пробелы) - [Фигурные скобки](#фигурные-скобки) - [Круглые скобки](#круглые-скобки) - [Использование конструкции switch](#использование-конструкции-switch) - [Разрыв строк](#разрыв-строк) - [Использование исключений](#использование-исключений) - [Наследование и ключевое слово virtual](#наследование-и-ключевое-слово-virtual) - [Неявные преобразования](#неявные-преобразования) - [Числа с плавающей запятой](#числа-с-плавающей-запятой) - [Преинкремент и предекремент](#преинкремент-и-предекремент) - [Другие очевидные вещи](#другие-очевидные-вещи) - [Общее исключение](#общее-исключение)
## Кодировка Единственной кодировкой должна быть UTF-8, а использование других следует приравнять к разжиганию межнациональной розни и карать соответствующей статьёй УК.
[наверх](#содержание)
## Заголовочные файлы При включении заголовочных файлов Qt, всегда используйте следующую форму записи: ```C #include ``` Префикс библиотеки (`QtCore`, `QtWidgets` и т.д.) необходим для фреймворков Mac OS X, а также очень целесообразен для не qmake проектов.
Все заголовочные файлы должны быть с защитой от повторного включения посредством `#pragma once` или `#define`. Применение `#pragma once` вместо `#define` увеличит скорость компиляции во многих случаях благодаря высокоуровневому механизму; компилятор может самостоятельно сравнивать имена файлов или inode'ы без необходимости вызова препроцессора для проверки заголовка на наличие `#ifndef` и `#endif`. Можно использовать обе команды, `#pragma once` и `#define`, для написания переносимого кода, что также может принести выгоду от применения `#pragma once` при оптимизации (если компилятор её поддерживает): ```C #pragma once #ifndef FOO_BAR_BAZ_H_ #define FOO_BAR_BAZ_H_ //... #endif // FOO_BAR_BAZ_H_ ``` - Все заголовочные файлы должны быть самодостаточными в плане компиляции. Пользователи и инструменты разработки не должны зависеть от специальных зависимостей при использовании заголовочного файла. - Подключайте только действительно используемые заголовочные файлы. Не надо заранее подключать кучу `.h` файлов "на всякий случай". - Никогда не пишите реализацию методов класса или функций в заголовочном файле! - Вставляйте заголовочные файлы в следующем порядке: парный файл (например, foo.h — foo.cpp), файлы библиотеки Qt, стандартная библиотека C++, другие библиотеки, файлы вашего проекта. - Все заголовочные файлы проекта должны указываться относительно директории исходных файлов проекта без использования таких псевдонимов как . (текущая директория) или .. (родительская директория). Директории поиска общих заголовочных файлов можно задать в файле проекта.
[наверх](#содержание)
## Директивы препроцессора Символ решетки всегда в начале строки, а имя директивы с отступом. ```C # if defined(QT_NO_KEYWORDS) # define QT_NO_EMIT # else # ifndef QT_NO_SIGNALS_SLOTS_KEYWORDS # define slots Q_SLOTS # define signals Q_SIGNALS # endif # endif ```
[наверх](#содержание)
## Отступы - Для обозначения отступа используйте 4 пробела подряд. - Используйте пробелы, а не табуляцию!
[наверх](#содержание)
## Объявление переменных, функций и классов Один из самых важных постулатов, так как определяет читабельность и общий стиль кода. Правила объявления переменных собраны в такой список: - Объявляйте по одной переменной в строке. - Избегайте, если это возможно, коротких и запутанных названий переменных (Например: "a", "rbarr", "nughdeget"). - Односимвольные имена переменных подходят только для итераторов циклов, небольшого локального контекста и временных переменных. В остальных случаях имя переменной должно отражать ее назначение. - Заводите переменные только по мере необходимости. ```C // Неправильно: int a, b; char *c, *d; // Правильно: int height; int width; char *nameOfThis; char *nameOfThat; ``` - Не используйте глобальные переменные. Вместо них рекомендуется использовать локальные переменные и передавать их через параметры функций. - Функции и переменные должны именоваться со строчной буквы. Каждое последующие слово в имени переменной должно начинаться с прописной буквы. - Избегайте аббревиатур. ```C // Неправильно short Cntr; char ITEM_DELIM = ' '; // Правильно short counter; char itemDelimiter = ' '; ``` - Имена классов всегда начинаются с заглавной буквы. - Сокращения в camel case (правильно: `QXmlStreamReader`, не правильно: `QXMLStreamReader`).
Размещайте свой код в пространстве имён (за некоторыми исключениями). Пространство имён должно иметь уникальное имя, обычно формируемое на основе названия проекта, и, возможно, пути. Не используйте директиву `using` (например, `using namespace foo`). Не используйте встроенные (`inline`) пространства имён. Пространства имён делят глобальную область видимости на отдельные именованные области, позволяя избежать совпадения (коллизий) имён.
[наверх](#содержание)
## Пробелы Пробелы — очень важный элемент форматирования исходного кода. Он отыгрывает очень большую роль в читабельности кода. - Используйте пустые строки для логической группировки операторов, где это возможно. - Всегда используйте одну пустую строку в качестве разделителя - Всегда используйте один пробел перед фигурной скобкой ```C // Неправильно: if(foo){ } // Правильно: if (foo) { } ``` - Всегда ставьте один пробел после `'*'` или `'&'`, если они стоят перед описанием типов. Но никогда не ставьте пробелы между `'*'` или `'&'` и именем переменной. ```C char *x; const QString &myString; const char * const y = "hello"; ``` - Не окружайте пробелами функции доступа `.` и `->`. - Бинарные операции отделяются пробелами с двух сторон. - После преобразования типов не ставьте пробелов. - Избегайте преобразования типов в стиле C. ```C // Неправильно char* blockOfMemory = (char* ) malloc(data.size()); // Правильно char *blockOfMemory = reinterpret_cast(malloc(data.size())); ``` - Не используйте несколько операторов на одной строке - По возможности, используйте новую строку для тела оператора ветвления: ```C // Неправильно: if (foo) bar(); // Правильно: if (foo) bar(); ``` - Содержимое в пространстве имён пишется без отступа. - Никогда не добавляйте пробелы в конец строки.
[наверх](#содержание)
## Фигурные скобки Скобки — это вообще отдельная тема. Они, как и пробелы, отыгрывают львиную долю во внешнем виде и читабельности кода. - Возьмите за основу расстановку открывающих фигурных скобок на одной строке с выражением, которому они предшествуют. - Исключение: Тело функции и описание класса всегда открывается фигурной скобкой, стоящей на новой строке. - Используйте фигурные скобки в условиях, если тело условия в размере превышает одну линию, или тело условия достаточное сложное и выделение скобками действительно необходимо. - Исключение 1: Используйте скобки, если родительское выражение состоит из нескольких строк / оберток. - Исключение 2: Используйте фигурные скобки, когда тела ветвлений `if-then-else` занимают несколько строчек. - Используйте фигурные скобки для обозначения пустого тела условия. ```C // Неправильно: if (codec) { // do something } // Правильно: if (codec) { // do something } // Неправильно: if (address.isEmpty() || !isValid() || !codec) return false; // Правильно: if (address.isEmpty() || !isValid() || !codec) { return false; } ```
[наверх](#содержание)
## Круглые скобки - Используйте круглые скобки для группировки выражений. ```C // Неправильно if (a && b || c) if (a + b & c) // Правильно if ((a && b) || c) if ((a + b) & c) ```
[наверх](#содержание)
## Использование конструкции switch Безусловно, эти условия причина многих дискуссий со стороны разработчиков и создателей Coding Guidelines — там может быть очень много различных вариантов. Однако Qt предлагает именно такой вариант: - Операторы case должны быть в одном столбце со `switch`. - Каждый оператор `case` должен иметь закрывающий `break` (или `return`) или комментарий, которой предполагает намеренное отсутствие `break & return`. ```C switch (myEnum) { case Value1: doSomething(); break; case Value2: case Value3: doSomethingElse(); // fall through default: defaultHandling(); break; } ```
[наверх](#содержание)
## Разрыв строк Часто происходит следующее: есть разработчик Вася с большим монитором. Он пишет себе код спокойно. Потом этот код открывает разработчик Петя, с ноутбуком, и прозревает — ему приходится много скроллить чтобы прочитать весь код. Это один из дефектов читабельности. Что же предлагает Qt для спасения? - Длина строки кода не должна превышать 100 символов (а лучше 80 - исторический стандарт). Если надо – используйте разрыв строки. - Запятые помещаются в конец разорванной линии; операторы помещаются в начало новой строки. В зависимости от используемой вами IDE, оператор на конце разорванной строки можно проглядеть. ```C // Неправильно: if (longExpression + otherLongExpression + otherOtherLongExpression) { } QMessageBox::information(d->someObjectWithLongName, tr("A long title for mesage"), tr("A very very very very very very long body"), QMessageBox::Ok, QMessageBox::Cancel); // Правильно: if (longExpression + otherLongExpression + otherOtherLongExpression) { } QMessageBox::information(d->someObjectWithLongName, tr("A long title for mesage"), tr("A very very very very very very long body"), QMessageBox::Ok, QMessageBox::Cancel); ```
[наверх](#содержание)
## Использование исключений В Qt исключения (`throw `) не используются. Вместо них применяются коды ошибок.
[наверх](#содержание)
## Наследование и ключевое слово virtual В этом постулате все предельно просто — главное не писать `virtual` перед названием переопределяемого метода в `.h` файле. ```C // Неправильно: class MyWidget : public QWidget { ... protected: virtual void keyPressEvent(QKeyEvent *); // Правильно: class MyWidget : public QWidget { ... protected: void keyPressEvent(QKeyEvent *) override; ```
[наверх](#содержание)
## Неявные преобразования Не объявляйте неявные преобразования. Используйте ключевое слово `explicit` для операторов преобразования типа и конструкторов с одним аргументом. Исключение: конструкторы копирования и перемещения могут объявляться без `explicit`, т.к. они не выполняют преобразование типов.
[наверх](#содержание)
## Числа с плавающей запятой Числа с плавающей запятой всегда должны быть с десятичной точкой и числами по обе стороны от неё (даже в случае экспоненциальной нотации). ```C // Неправильно: float f = 1.f; long double ld = -.5L; double d = 1248e6; // Правильно: float floatValue = 1.0f; float floatVariable = 1.0; // OK double doubleValue = 1248.0e6; ```
[наверх](#содержание)
## Преинкремент и предекремент Используйте префиксные формы (`++i`) инкремента и декремента; постфиксную форму используйте только при явной необходимости. Когда переменная инкрементируется (`++i`, `i++`) или декрементируется (`--i`, `i--`), а возвращаемое значение не используется, то необходимо чётко понимать: использовать префиксную форму (`++i`, `--i`) или постфиксную (`i++`, `i--`).
Префиксную форму обычно легче читать, и она часто более эффективна (как минимум такая же), т.к. не требуется создавать копию значения до выполнения операции. ```C // Неправильно: for (int i = 0; i < size; i++) { // Правильно: for (int i = 0; i < size; ++i) { ```
[наверх](#содержание)
## Другие очевидные вещи Еще некоторые правила, которые всегда должны выполняться, их все знают, но повторим на всякий случай: - Не используйте `goto` и другие устаревшие конструкции, которые нарушают принципы стандарта программирования. - По возможности не используйте в проектах `qmake`, старайтесь новые проекты строить с использованием `cmake` актуальной версии. - Всегда включайте в свои файлы проектов расширренную проверку на ошибки. Для компилятора `gcc` (`mingw`) это делается добавлением строчки в `CMakeList.txt`: ```CMake target_compile_options(${PROJECT_NAME} PRIVATE -Werror -Wall -Wextra -Wpedantic) ``` - Также можно выключать устаревшие конструкции языка. Пример для выключения `foreach`: ```CMake target_compile_definitions(${PROJECT_NAME} PRIVATE QT_NO_FOREACH) ``` - Пользуйтесь системой управления версиями. - Пишите по возможности кроссплатформенный код (как минимум поддерживаемый Windows и Linux). Используйте условную компиляцию для кода, специфичного для определенной ОС: ```C # if defined (Q_OS_WINDOWS) // код для Windows # else // код для Linux, MacOS # endif ``` - Для указателей (адресов) используйте `nullptr`, это улучшает безопасность типов. Используйте `'\0'` в качестве символа конца строки (пустого символа). Это улучшает читабельность кода. - Рекомендуется использовать `sizeof(переменная)` вместо `sizeof(тип)`. - Не вставляйте бесполезные комментарии в код. Ваш код должен быть самодокументируемым. Комментарии можно использовать для отдельных пояснений неочевидных или специфических вещей: ```C // Плохо: int counter; // - счетчик шагов // Хорошо: int stepCounter {0}; ```
[наверх](#содержание)
## Общее исключение Этот постулат гласит нам, что нет ничего плохого если вы нарушите какое-то правило, но только в том случае, если оно делает ваш код уродливым. Это хороший пример того, что у всех правил есть исключения, и того, что правила созданы чтобы их нарушать.
К сожалению, я не смог найти примера, когда `Qt Coding Guidelines` делают код — уродливым.
[наверх](#содержание)
---
- [К списку документов](Readme.md)