10 особенностей С++, о которых знают лишь опытные программисты
Многие функции реализованы в С++, однако не обо всех знают простые программисты. 10 особенностей языка, которые помогут повысить ваш уровень мастерства.
1. Условные операторы
Большая часть разработчиков, работающих с С++, знают и используют условные операторы.
x = (y < 0) ? 10 : 20;
Но не все программисты понимают, что их также можно использовать в качестве передаваемого значения:
(a == 0 ? a : b) = 1;
Что является сокращением следующего:
if (a == 0) a = 1; else b = 1;
Стоит применять с осторожностью.
2. URI в С++
У вас есть возможность поместить URI в исходники C++ без получения ошибок. Например:
void foo() { http://stackoverflow.com/ int bar = 4; ... }
3. Арифметика указателей
Использование указателей при написании кода чревато появлением огромного количества ошибок. По этой причине программисты на С++ стараются их избегать. Альтернативой могут послужить числовые литералы.
4. Шаблоны и функции
Многие возможности языка можно реализовать только благодаря различным сторонним библиотекам.
RAII - одна из главных и наиболее важных функций, которая часто остается без должного внимания программистов, пришедших из мира С. Как и зачем перегружать операторы, многие не понимают до сих пор, а между тем это позволяет осуществить поведение, характерное для массивов. Это умные указатели и перемножение матриц.
Исключения - не самый простой инструмент, но немного поработав с ним, можно сделать код более устойчивым за счет спецификаций безопасности исключений (код не будет крашиться или будет восстановлен до исходного состояния).
Самая известная из функций С++ - метапрограммирование шаблонов. С ее помощью код либо частями, либо полностью выполнится за время компилирования, а не во время выполнения. Но для того, чтобы работать с ней, вам потребуются значительные знания шаблонов проектирования.
Иные варианты использования множественной парадигмы позволяют создавать способы программирования вне языка С - предка С++:
Функторы: предоставляют возможность симулировать функции с дополнительной типобезопасностью и способностью сохранения состояния.
Команда: этот шаблон проектирования позволяет отложить выполнение кода. Большинство других шаблонов позволят легко и эффективно реализовать стили программирования, не входящие в список “официальных парадигм С++”. Кроме того, их использование улучшит типобезопасность (благодаря автоматизированным malloc/realloc/free).
Объекты в C++ действительно обладают достаточным функционалом, неправильное использование которого приведет к большим трудностям, но даже динамический полиморфизм имеет свою статическую версию: CRTP.
Наиболее предпочтительный способ добавить объекту функции, который при этом будет в духе объектно-ориентированного программирования - сделать это с помощью non-member non-friend функции, а не просто функции-члена. Да, волосы многих Java-разработчиков сейчас встали дыбом, но это действительно так. А все потому что:
- В С++ как функции-члены, так и non-member функции находятся в одном пространстве имен.
- функции-члены non-member функции не обладают привилегированным доступом к внутренностям класса. Из этого выходит, что использование non-member non-friend функции функцией-членом ослабит инкапсуляцию класса.
5. Псевдоним для namespace alias
До некоторого времени это не было известно никому, кроме тех, кто читал дополнительную документацию. Теперь информацию об этом можно найти в каждой ссылке по С++.
namespace fs = boost::filesystem; fs::path myPath( strPath, fs::native );
6. Объявление классов и функций
В init части цикла for можно объявлять не одни лишь переменные. Здесь также можно разместить классы и функции.
for(struct { int a; float b; } loop = { 1, 2 }; ...; ...) { ... }
Благодаря этому можно использовать множество переменных с разными типами.
7. Ассоциативность оператора массива
A[8] - это то же самое, что и *(A + 8). Так как операция сложения ассоциативна, она может быть переписана как *(8 + A), что синонимично ..... 8[A]
Никто не говорил, что это должно быть обязательно полезно... :-)
8. Объединения тоже могут быть шаблонами
Еще одна вещь, о которой знают немногие, это то, что объединения тоже могут быть шаблонами:
template union union_cast { From from; To to; union_cast(From from) :from(from) { } To getTo() const { return to; } };
У них также могут быть конструкторы и функции-члены. Ничего общего с наследованием(включая виртуальные функции).
9. Метапрограммирование
C++ - это язык программирования, в котором существует несколько парадигм. Они позволяют расширить функционал языка. Так, например, в нем существует метапрограммирование шаблонов. Вероятно, никто не ожидал, что оно позволит стать языку Тьюринг-полным подъязыком, способным исполняться во время компиляции.
10. Унарный оператор +
Многие не подозревают о возможностях унарного оператора +, функциональность которого недоступна при разработке на С. Он может быть использован во многих случаях:
Перевод Enumeration в integer
+AnEnumeratorValue
И значение вашего перечислителя, которое имело тип перечисления сейчас стало типом integer с соответствующим ему значением. Это пригодится в случае, если вы захотите реализовать перегруженный оператор для своего перечисления.
Получение значения переменной
Вам нужно использовать класс, который использует встроенный статический инициализатор без внешнего объявления, но сделать это не удается? С помощью оператора можно создать временный класс, который не будет зависим от типа
struct Foo { static int const value = 42; }; // Пытается делать что-то интересное... template void f(T const&); int main() { // не получилось связать- пробуем получить адрес f(Foo::value); // работает - передает временное значение f(+Foo::value); }
Разложение массива на указатели
Вам необходимо передать два указателя какой-либо функции, однако вы наперед знаете, что ничего из этого не выйдет? В этом случае вам очень пригодится оператор:
// Это делает кое-что интересное... template void f(T const& a, T const& b); int main() { int a[2]; int b[3]; f(a, b); // не работает! разные значения для "T"! f(+a, +b); // работает! T это "int*" в обоих случаях }