
Привет, хабражители!
Сейчас какой-то спец с многолетним опытом работы с Qt подумал: «Что за фигня? Хабр — для вещей покруче!». Но ведь даже спецам с многолетним опытом иногда надо читать вот такие статьи про простые вещи, ведь это — важно. Код — это одна из самых важных составляющих программирования. А наша задача — держать его в чистоте. Эта статья посвящена всем Qt программистам которые стремятся к идеалу.
Конечно есть статья на Qt Project — Qt Coding Style. Только вот там материала ценного меньше…
Постулат №1. Выравнивание
В Qt принято использовать отступы по 4 пробела. Но именно 4, и именно пробела. Использовать \t или другую ширину пробелов считается ужасно плохим тоном
Постулат №2. Объявление переменных
Один из самых важных постулатов, так как определяет читабельность и общий стиль кода. Правила объявления переменных собраны в такой список:
- Объявлять каждую переменную на отдельной строчке
- Избегать коротких или немногословных названий (например «a», «rbarr», «nughdeget»)
- Дождитесь, пока переменная будет нужна, и только тогда объявляйте ее
- Функции и переменные должны быть в camelCase
- Избегайте аббревиатур и всяческих сокращений
- Классы всегда должны начинаться с заглавной буквы
- Публичные классы должны начинаться с буквы ‘Q’ (QRgb), затем заглавная буква
- Публичные функции должны начинаться с буквы ‘q’ (qRgb)
- Аббревиатуры должны быть в PascalCase (например QXmlStreamReader вместо QXMLStreamReader)
// Неправильно int a, b; char *c, *d; // Правильно int height; int width; char *nameOfThis; char *nameOfThat;
// Неправильно short Cntr; char ITEM_DELIM = '\t'; // Правильно short counter; char itemDelimiter = '\t';
Постулат №3. Пробелы
Пробелы — очень важный элемент форматирования исходного кода. Он отыгрывает очень большую роль в читабельности кода.
- Используйте пробелы для группировки отдельных сегментов кода
- Для разделения можно использовать только одну пустую линию
- Всегда использовать только один, и только один пробел после ключевого слова и фигурной скобки
- Для указателей и ссылок, всегда используйте один пробел между типом и ‘*’ или ‘&’, но никогда не ставьте пробел между ‘*’ или ‘&’ и названием переменной
- Окружайте бинарные операторы пробелами
- Никаких пробелов после приведения типов
- Старайтесь избегать С-подобных приведений
// Неправильно if (foo){ } // Правильно if (foo) { }
char *x; const QString &myString; const char * const y = "hello"; MyClass *obj = new MyClass(this); bool ok; obj.report(1, &ok);
// Неправильно char* blockOfMemory = (char* ) malloc(data.size()); QTextStrem newOne(..); newOne<<"Hello"<<","<<" "<<"world"; // Правильно char *blockOfMemory = reinterpret_cast<char *>(malloc(data.size())); QTextStrem newOne(..); newOne<< "Hello" << "," << " " << "world";
Постулат №4. Скобки
Скобки — это вообще отдельная тема. Они, как и пробелы, отыгрывают львиную долю во внешнем виде и читабельности кода
- В качестве основного правила, левая фигурная скобка находится на той же строчке, что и оператор:
- Исключение: Реализация функций и объявления классов всегда, абсолютно всегда располагают левую скобку на новой строчке:
- Используйте фигурные скобки когда тело условия содержит более одной линии, и если однострочный оператор — что-то комплексное
- Исключение 1: Также используйте скобки если родительский оператор занимает несколько линий или оберток
- Исключение 2: Также используйте скобки в if-else блоках где if-код или else-код занимает несколько линий
- Используйте фигурные скобки когда тело оператора — пустое
static void foo(int g) { qDebug("foo: %i", g); } class Moo { public: Moo(); Moo(int a, int b); public slots: int getResult(); protected slots: void processNumbers(); private: int mineA; int mineB; int mineResult; };
// Неправильно if (address.isEmpty()) { return false; } for (int i = 0; i < 10; ++i) { qDebug("%i", i); } // Правильно if (address.isEmpty()) return false; for (int i = 0; i < 10; ++i) qDebug("%i", i);
// Неправильно while (a); if (expression) else // do something // Правильно while (a) {} if (expression) { } else { // do something }
// Неправильно if (codec) { // do something } // Правильно if (codec) { // do something }
// Неправильно if (address.isEmpty()) return false; else { qDebug("%s", qPrintable(address)); ++it; } // Правильно if (address.isEmpty()) { return false; } else { qDebug("%s", qPrintable(address)); ++it; } // Неправильно if (a) if (b) ... else ... // Правильно if (a) { if (b) ... else ... }
// Неправильно if (address.isEmpty() || !isValid() || !codec) return false; // Правильно if (address.isEmpty() || !isValid() || !codec) { return false; }
Постулат №5. Круглые скобки
Используйте круглые скобки чтобы группировать выражения:
// Неправильно if (a && b || c) if (a + b & c) // Правильно if ((a && b) || c) if ((a + b) & c)
Постулат №6. Условия множественного выбора switch
Безусловно, эти условия причина многих дискуссий со стороны разработчиков и создателей Coding Guidelines — там может быть очень м��ого различных вариантов. Однако Qt предлагает именно такой вариант:
- Операторы case должны находиться в той же колонке, что и оператор switch
- Каждый случай должен заканчиваться оператором break (или return) или комментарием, чтобы показать чтоe далее следует другой случай
switch (myEnum) { case Value1: doSomething(); break; case Value2: case Value3: doSomethingElse(); // fall through default: defaultHandling(); break; }
Постулат №7. Разрыв строк
Часто происходит следующее: есть разработчик Вася с большим монитором. Он пишет себе код спокойно. Потом этот код открывает разработчик Петя, с ноутбуком, и прозревает — ему приходится много скроллить чтобы прочитать весь код. Это один из дефектов читабельности. Что же предлагает Qt для спасения?
- Старайтесь чтобы строки были не длиннее 100 символов; обрывайте их, если это необходимо
- Коммы располагаются в конце оборванной строки; операторы следует переносить в начале новой строки. Оператор в конце строки очень просто не увидеть если ваш редактор слишком узкий
// Неправильно 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);
UPD: последний участок кода отображается неверное — там все строчки до��жны быть на одном уровне
Постулат №8. Наследование и ключевое слово `virtual`
В этом постулате все предельно просто — главное не писать `virtual` перед названием переопределяемого метода в .h файле.
// Неправильно class MyWidget : public QWidget { ... protected: virtual void keyPressEvent(QKeyEvent *); // Правильно class MyWidget : public QWidget { ... protected: void keyPressEvent(QKeyEvent *);
Постулат №9. Общее исключение
Этот постулат гласит нам, что нет ничего плохого если вы нарушите какое-то правило, но только в том случае, если оно делает ваш код уродливым. Это хороший пример того, что у всех правил есть исключения, и того, что правила созданы чтобы их нарушать.
К сожалению, я не смог найти примера, когда Qt Coding Guidelines делают код — уродливым.
Завершение
Боюсь что это конец моей статьи про стиль написания кода в Qt. Еще раз напомню что только он котируется для контрибьютинга в Qt, так что если вы собираетесь внести свою лепту в развитие проекта, вам так или иначе придется использовать эти постулаты, но не забывайте — правила можно нарушать:).
Для меня — Qt Coding Style просто идеальный стиль для написания кода. Я считаю его чистым, удобным, приятным. За все время его использования у меня не возникло никаких проблем с читабельностью кода. Буду ли я его рекомендовать? Конечно, да! Тем более, я считаю что именно его и надо пропагандировать всем новичкам на платформе Qt.
Спасибо за внимание.