C++ (читается си-плюс-плюс[2][3]) — компилируемый, статически типизированный язык программирования общего назначения.
C++ | |
---|---|
![]() | |
Семантика | мультипарадигмальный: объектно-ориентированное, обобщённое, процедурное, метапрограммирование |
Класс языка | объектно-ориентированный язык программирования, мультипарадигмальный язык программирования, процедурный язык программирования, язык функционального программирования, язык обобщённого программирования[d], язык программирования, free-form language[d] и компилируемый язык программирования |
Тип исполнения | компилируемый |
Появился в | 1983 |
Автор | Страуструп, Бьёрн |
Расширение файлов |
.cc , .cpp , .cxx , .c , .c++ , .h , .hpp , .hh , .hxx или .h++ |
Выпуск | |
Система типов | статическая |
Основные реализации | GNU C++, Microsoft Visual C++, Intel C++ compiler, Open64 C++ Compiler, Clang, Comeau C/C++ , Embarcadero C++ Builder, Watcom C++ compiler, Digital Mars C++, Oracle Solaris Studio C++ compiler, Turbo C++ |
Диалекты | ISO/IEC 14882 C++ |
Испытал влияние | Си, Симула, Алгол 68, Клу, ML и Ада |
Сайт | isocpp.org (англ.) |
![]() |
Поддерживает такие парадигмы программирования, как процедурное программирование, объектно-ориентированное программирование, обобщённое программирование. Язык имеет богатую стандартную библиотеку, которая включает в себя распространённые контейнеры и алгоритмы, ввод-вывод, регулярные выражения, поддержку многопоточности и другие возможности. C++ сочетает свойства как высокоуровневых, так и низкоуровневых языков[4][5]. В сравнении с его предшественником — языком C — наибольшее внимание уделено поддержке объектно-ориентированного и обобщённого программирования[5].
C++ широко используется для разработки программного обеспечения, являясь одним из самых популярных языков программирования[мнения 1][мнения 2]. Область его применения включает создание операционных систем, разнообразных прикладных программ, драйверов устройств, приложений для встраиваемых систем, высокопроизводительных серверов, а также компьютерных игр. Существует множество реализаций языка C++, как бесплатных, так и коммерческих и для различных платформ. Например, на платформе x86 это GCC, Visual C++, Intel C++ Compiler, Embarcadero (Borland) C++ Builder и другие. C++ оказал огромное влияние на другие языки программирования, в первую очередь на Java и C#.
Синтаксис C++ унаследован от языка C. Изначально одним из принципов разработки было сохранение совместимости с C. Тем не менее C++ не является в строгом смысле надмножеством C; множество программ, которые могут одинаково успешно транслироваться как компиляторами C, так и компиляторами C++, довольно велико, но не включает все возможные программы на C.
Исторический этап развития[6] | Год |
---|---|
Язык BCPL | 1966 |
Язык Би (оригинальная разработка Томпсона под UNIX) | 1969 |
Язык Си | 1972 |
Си с классами | 1980 |
C84 | 1984 |
Cfront (выпуск E) | 1984 |
Cfront (выпуск 1.0) | 1985 |
Множественное/виртуальное наследование | 1988 |
Обобщённое программирование (шаблоны) | 1991 |
ANSI C++ / ISO-C++ | 1996 |
ISO/IEC 14882:1998 | 1998 |
ISO/IEC 14882:2003 | 2003 |
C++/CLI | 2005 |
TR1 | 2005 |
C++11 | 2011 |
C++14 | 2014 |
C++17 | 2017 |
C++20 | 2020 |
Язык возник в начале 1980-х годов, когда сотрудник фирмы Bell Labs Бьёрн Страуструп придумал ряд усовершенствований к языку C под собственные нужды[7]. Когда в конце 1970-х годов Страуструп начал работать в Bell Labs над задачами теории очередей (в приложении к моделированию телефонных вызовов), он обнаружил, что попытки применения существующих в то время языков моделирования оказываются неэффективными, а применение высокоэффективных машинных языков слишком сложно из-за их ограниченной выразительности. Так, язык Симула имеет такие возможности, которые были бы очень полезны для разработки большого программного обеспечения, но работает слишком медленно, а язык BCPL достаточно быстр, но слишком близок к языкам низкого уровня и не подходит для разработки большого программного обеспечения.
Вспомнив опыт своей диссертации, Страуструп решил дополнить язык C (преемник BCPL) возможностями, имеющимися в языке Симула. Язык C, будучи базовым языком системы UNIX, на которой работали компьютеры Bell, является быстрым, многофункциональным и переносимым. Страуструп добавил к нему возможность работы с классами и объектами. В результате практические задачи моделирования оказались доступными для решения как с точки зрения времени разработки (благодаря использованию Симула-подобных классов), так и с точки зрения времени вычислений (благодаря быстродействию C). В первую очередь в C были добавлены классы (с инкапсуляцией), наследование классов, строгая проверка типов, inline-функции и аргументы по умолчанию. Ранние версии языка, первоначально именовавшегося «C with classes» («Си с классами»), стали доступны с 1980 года.
Разрабатывая C с классами, Страуструп написал программу cfront — транслятор, перерабатывающий исходный код C с классами в исходный код простого C. Это позволило работать над новым языком и использовать его на практике, применяя уже имеющуюся в UNIX инфраструктуру для разработки на C. Новый язык, неожиданно для автора, приобрёл большую популярность среди коллег и вскоре Страуструп уже не мог лично поддерживать его, отвечая на тысячи вопросов.
К 1983 году в язык были добавлены новые возможности, такие как виртуальные функции, перегрузка функций и операторов, ссылки, константы, пользовательский контроль над управлением свободной памятью, улучшенная проверка типов и новый стиль комментариев (//
). Получившийся язык уже перестал быть просто дополненной версией классического C и был переименован из C с классами в «C++». Его первый коммерческий выпуск состоялся в октябре 1985 года.
До начала официальной стандартизации язык развивался в основном силами Страуструпа в ответ на запросы программистского сообщества. Функцию стандартных описаний языка выполняли написанные Страуструпом печатные работы по C++ (описание языка, справочное руководство и так далее). Лишь в 1998 году был ратифицирован международный стандарт языка C++: ISO/IEC 14882:1998 «Standard for the C++ Programming Language»; после принятия технических исправлений к стандарту в 2003 году — следующая версия этого стандарта — ISO/IEC 14882:2003[8].
В 1985 году вышло первое издание «Языка программирования C++», обеспечивающее первое описание этого языка, что было чрезвычайно важно из-за отсутствия официального стандарта. В 1989 году состоялся выход C++ версии 2.0. Его новые возможности включали множественное наследование, абстрактные классы, статические функции-члены, функции-константы и защищённые члены. В 1990 году вышло «Комментированное справочное руководство по C++», положенное впоследствии в основу стандарта. Последние обновления включали шаблоны, исключения, пространства имён, новые способы приведения типов и булевский тип. В качестве основы для хранения и доступа к обобщённым алгоритмам была выбрана Стандартная библиотека шаблонов (STL), разработанная Александром Степановым и Менг Ли .
Стандартная библиотека C++ также развивалась вместе с ним. Первым добавлением к стандартной библиотеке C++ стали потоки ввода-вывода, обеспечивающие средства для замены традиционных функций C printf
и scanf
. Позднее самым значительным развитием стандартной библиотеки стало включение в неё Стандартной библиотеки шаблонов.
C++ продолжает развиваться, чтобы отвечать современным требованиям. Одна из групп, разрабатывающих язык C++ и направляющих комитету по стандартизации C++ предложения по его улучшению — это Boost, которая занимается, в том числе, совершенствованием возможностей языка путём добавления в него особенностей метапрограммирования.
Никто не обладает правами на язык C++, он является свободным. Однако сам документ стандарта языка (за исключением черновиков) не доступен бесплатно[10]. В рамках процесса стандартизации, ISO выпускает несколько видов изданий. В частности, технические доклады и технические характеристики публикуются, когда «видно будущее, но нет немедленной возможности соглашения для публикации международного стандарта.» До 2011 года было опубликовано три технических отчёта по C++: TR 19768: 2007 (также известный как C++, Технический отчёт 1) для расширений библиотеки в основном интегрирован в C++11, TR 29124: 2010 для специальных математических функций, и TR 24733: 2011 для десятичной арифметики с плавающей точкой. Техническая спецификация DTS 18822:. 2014 (по файловой системе) была утверждена в начале 2015 года, и остальные технические характеристики находятся в стадии разработки и ожидают одобрения[11].
В марте 2016 года в России была создана рабочая группа РГ21 C++. Группа была организована для сбора предложений к стандарту C++, отправки их в комитет и защиты на общих собраниях Международной организации по стандартизации (ISO)[12].
Имя языка, полученное в итоге, происходит от оператора унарного постфиксного инкремента C ++
(увеличение значения переменной на единицу). Имя C+ не было использовано потому, что является синтаксической ошибкой в C и, кроме того, это имя было занято другим языком. Язык также не был назван D, поскольку «является расширением C и не пытается устранять проблемы путём удаления элементов C»[7].
В книге «Дизайн и эволюция C++»[13] Бьёрн Страуструп описывает принципы, которых он придерживался при проектировании C++. Эти принципы объясняют, почему C++ именно такой, какой он есть. Некоторые из них:
Стандарт C++ состоит из двух основных частей: описание ядра языка и описание стандартной библиотеки.
Первое время язык развивался вне формальных рамок, спонтанно, по мере встававших перед ним задач. Развитию языка сопутствовало развитие кросс-компилятора cfront. Новшества в языке отражались в изменении номера версии кросс-компилятора. Эти номера версий кросс-компилятора распространялись и на сам язык, но применительно к настоящему времени речь о версиях языка C++ не ведут. Лишь в 1998 году язык стал стандартизированным.
/* комментарий */
), так и однострочные (// вся оставшаяся часть строки является комментарием
), где //
обозначает начало комментария, а ближайший последующий символ новой строки, который не предварён символом \
(либо эквивалентным ему обозначением ??/
), считается окончанием комментария. Плюс этого комментария в том, что его не обязательно заканчивать, то есть обозначать окончание комментария.inline
для функций. Функция, определённая внутри тела класса, является inline по умолчанию. Данный спецификатор является подсказкой компилятору и может встроить тело функции в код вместо её непосредственного вызова.const
и volatile
. В отличие от С, где const
обозначает только доступ на чтение, в C++ переменная с квалификатором const
должна быть инициализирована. volatile
используется в описании переменных и информирует компилятор, что значение данной переменной может быть изменено способом, который компилятор не в состоянии отследить. Для переменных, объявленных volatile
, компилятор не должен применять средства оптимизации, изменяющие положение переменной в памяти (например, помещающие её в регистр) или полагающиеся на неизменность значения переменной в промежутке между двумя присваиваниями ей значения. В многоядерной системе volatile
помогает избегать барьеров памяти 2-го типа[источник не указан 3586 дней].namespace
). Пример:namespace Foo
{
const int x = 5;
}
const int y = Foo::x;
Специальным случаем является безымянное пространство имён. Все имена, описанные в нём, доступны только в текущей единице трансляции и имеют локальное связывание. Пространство имён std
содержит в себе стандартные библиотеки C++.
new
, new[]
, delete
и delete[]
. В отличие от библиотечных malloc и free, пришедших из C, данные операторы производят инициализацию объекта. Для классов это вызов конструктора, для
В C++ доступны следующие встроенные типы. Типы C++ практически полностью повторяют типы данных в C:
char
, wchar_t
(char16_t
и char32_t
, в стандарте C++11);signed char
, short int
, int
, long int
(и long long
, в стандарте C++11);unsigned char
, unsigned short int
, unsigned int
, unsigned long int
(и unsigned long long
, в стандарте C++11);float
, double
, long double
;bool
, имеющий значения либо true
, либо false
.Операции сравнения возвращают тип bool
. Выражения в скобках после if
, while
приводятся к типу bool
[14].
Язык ввёл понятие ссылок, а со стандарта C++11 rvalue-ссылки и передаваемые ссылки (англ. forwarding reference). (см. Ссылка (C++))
C++ добавляет к C объектно-ориентированные возможности. Он вводит классы, которые обеспечивают три самых важных свойства ООП: инкапсуляцию, наследование и полиморфизм.
В стандарте C++ под классом (class) подразумевается пользовательский тип, объявленный с использованием одного из ключевых слов class
, struct
или union
, под структурой (structure) подразумевается класс, определённый через ключевое слово struct
, и под объединением (union) подразумевается класс, определённый через ключевое слово union
. В зависимости от использованного ключевого слова, меняются также и некоторые свойства самого класса. Например, в классе, объявленным через struct
, члены без вручную прописанного модификатора доступа будут по умолчанию иметь публичный уровень доступа, а не приватный.
В теле определения класса можно указать как объявления функций, так и их определение. В последнем случае функция является встраиваемой (inline
). Нестатические функции-члены могут иметь квалификаторы const
и volatile
, а также ссылочный квалификатор (&
или &&
).
C++ поддерживает множественное наследование. Базовые классы (классы-предки) указываются в заголовке описания класса, возможно, со спецификаторами доступа. Наследование от каждого класса может быть публичным, защищённым или закрытым:
Доступ члена базового класса/режим наследования | private-член | protected-член | public-член |
---|---|---|---|
private-наследование | недоступен | private | private |
protected-наследование | недоступен | protected | protected |
public-наследование | недоступен | protected | public |
По умолчанию базовый класс наследуется как private.
В результате наследования класс-потомок получает все поля классов-предков и все их методы; можно сказать, что каждый экземпляр класса-потомка содержит подэкземпляр каждого из классов-предков. Если один класс-предок наследуется несколько раз (это возможно, если он является предком нескольких базовых классов создаваемого класса), то экземпляры класса-потомка будет включать столько же подэкземпляров данного класса-предка. Чтобы избежать такого эффекта, если он нежелателен, C++ поддерживает концепцию виртуального наследования. При наследовании базовый класс может объявляться виртуальным; на все виртуальные вхождения класса-предка в дерево наследования класса-потомка в потомке создаётся только один под экземпляр.
C++ поддерживает динамический полиморфизм и параметрический полиморфизм.
Параметрический полиморфизм представлен:
void f(int x, int y=5, int z=10)
, вызовы f(1)
, f(1,5)
и f(1,5,10)
эквивалентны.void Print(int x);
void Print(double x);
void Print(int x, int y);
Динамический полиморфизм реализуется с помощью виртуальных методов и иерархии наследования. Полиморфным в C++ является тип имеющий хотя бы один виртуальный метод. Пример иерархии:
class Figure
{
public:
virtual void Draw() = 0; // чистый виртуальный метод
virtual ~Figure(); // при наличии хотя бы одного виртуального метода деструктор следует сделать виртуальным
};
class Square : public Figure
{
public:
void Draw() override;
};
class Circle : public Figure
{
public:
void Draw() override;
};
Здесь класс Figure является абстрактным (и, даже, интерфейсным), так как метод Draw не определён. Объекты данного класса нельзя создать, зато можно использовать ссылки или указатели с типом Figure. Выбор реализации метода Draw будет производиться во время выполнения исходя из реального типа объекта.
Инкапсуляция в C++ реализуется через указание уровня доступа к членам класса: они бывают публичными (открытыми, public
), защищёнными (protected
) и приватными (закрытыми, private
). В C++ структуры формально отличаются от классов лишь тем, что по умолчанию уровень доступа к членам класса и тип наследования у структуры публичные, а у класса — приватные.
Доступ | private | protected | public |
---|---|---|---|
Сам класс | да | да | да |
Друзья | да | да | да |
Наследники | нет | да | да |
Извне | нет | нет | да |
Проверка доступа происходит во время компиляции, попытка обращения к недоступному члену класса вызовет ошибку компиляции.
Функции-друзья — это функции, не являющиеся функциями-членами и тем не менее имеющие доступ к защищённым и закрытым членам класса. Они должны быть объявлены в теле класса как friend
. Например:
class Matrix {
friend Matrix Multiply(Matrix m1, Matrix m2);
};
Здесь функция Multiply
может обращаться к любым полям и функциям-членам класса Matrix
.
Дружественным может быть объявлен как весь класс, так и функция-член класса. Четыре важных ограничения, накладываемых на отношения дружественности в C++:
В общем виде это правило можно сформулировать следующим образом: «Отношение дружественности существует только между теми классами (классом и функцией), для которых оно явно объявлено в коде, и действует только в том направлении, в котором оно объявлено».
Класс по умолчанию может иметь шесть специальных функций: конструктор по умолчанию, конструктор копирования, конструктор перемещения, деструктор, оператор присваивания копированием, оператор присваивания перемещением. Также можно явно определить их все (см. Правило трёх).
class Array {
public:
Array() = default; // компилятор создаст конструктор по умолчанию сам
Array(size_t _len) :
len(_len) {
val = new double[_len];
}
Array(const Array & a) = delete; // конструктор копирования явно удалён
Array(Array && a); // конструктор перемещения
~Array() {
delete[] val;
}
Array& operator=(const Array& rhs); // оператор присваивания копированием
Array& operator=(Array&& rhs); // оператор присваивания перемещением
double& operator[](size_t i) {
return val[i];
}
const double& operator[](size_t i) const {
return val[i];
}
protected:
std::size_t len = 0; // инициализация поля
double* val {nullptr};
};
Конструктор вызывается для инициализации объекта (соответствующего типа) при его создании, а деструктор — для уничтожения объекта. Класс может иметь несколько конструкторов, но деструктор может иметь только один. Конструкторы в C++ не могут быть объявлены виртуальными, а деструкторы — могут, и обычно объявляются для всех полиморфных типов, чтобы гарантировать правильное уничтожение доступного по ссылке или указателю объекта независимо от того, какого типа ссылка или указатель. При наличии хотя бы у одного из базовых классов виртуального деструктора, деструктор класса потомка автоматически становится виртуальным.
Шаблоны позволяют порождать функции и классы, параметризованные определённым типом или значением. Например, предыдущий класс мог бы реализовывать массив для любого типа данных:
template <typename T>
class Array {
...
T& operator[](size_t i) {
return val[i];
}
protected:
std::size_t len {0}; // инициализация поля
T* val {nullptr};
};
Стандартная библиотека C++ включает в себя набор средств, которые должны быть доступны для любой реализации языка, чтобы обеспечить программистам удобное пользование языковыми средствами и создать базу для разработки как прикладных приложений самого широкого спектра, так и специализированных библиотек. Стандартная библиотека C++ включает в себя часть стандартной библиотеки C. Стандарт C++ содержит нормативную ссылку на стандарт C от 1990 года и не определяет самостоятельно те функции стандартной библиотеки, которые заимствуются из стандартной библиотеки C.
Доступ к возможностям стандартной библиотеки C++ обеспечивается с помощью включения в программу (посредством директивы #include
) соответствующих стандартных заголовочных файлов. Всего в стандарте C++11 определено 79 таких файлов. Средства стандартной библиотеки объявляются как входящие в пространство имён std. Заголовочные файлы, имена которых соответствуют шаблону «cX», где X — имя заголовочного файла стандартной библиотеки C без расширения (cstdlib, cstring, cstdio и пр.), содержат объявления, соответствующие данной части стандартной библиотеки C. Стандартные функции библиотеки C также находятся в пространстве имён std.
Стандартная библиотека включает в себя следующие разделы:
Контейнеры, строки, алгоритмы, итераторы и основные утилиты, за исключением заимствований из библиотеки C, собирательно называются STL (Standard Template Library — стандартная шаблонная библиотека). Изначально эта библиотека была отдельным продуктом и её аббревиатура расшифровывалась иначе, но потом она вошла в стандартную библиотеку C++ в качестве неотъемлемого элемента. В названии отражено то, что для реализации средств общего вида (контейнеров, строк, алгоритмов) использованы механизмы обобщённого программирования (шаблоны C++ — template). В работах Страуструпа подробно описываются причины, по которым был сделан именно такой выбор. Основными из них являются бо́льшая универсальность выбранного решения (шаблонные контейнеры, в отличие от объектных, могут легко использоваться для не объектных типов и не требуют наличия общего предка у типов элементов) и его техническая эффективность (как правило, операции шаблонного контейнера не требуют вызовов виртуальных функций и могут легко встраиваться (inline), что в итоге даёт выигрыш в производительности).
Начиная со стандарта C++11 добавились следующие возможности:
STL до включения в стандарт C++ была сторонней разработкой, вначале — фирмы HP, а затем SGI. Стандарт языка не называет её «STL», так как эта библиотека стала неотъемлемой частью языка, однако многие люди до сих пор используют это название, чтобы отличать её от остальной части стандартной библиотеки (потоки ввода-вывода (iostream), подраздел C и другие).
Проект под названием STLport[15], основанный на SGI STL, осуществляет постоянное обновление STL, IOstream и строковых классов. Некоторые другие проекты также занимаются разработкой частных применений стандартной библиотеки.
Выбор именно C в качестве базы для создания нового языка программирования объясняется тем, что язык C:
- является многоцелевым, лаконичным и относительно низкоуровневым языком;
- подходит для решения большинства системных задач;
- исполняется везде и на всём;
- стыкуется со средой программирования UNIX.
— Б. Страуструп. Язык программирования C++. Раздел 1.6[16]
Несмотря на ряд известных недостатков языка C, Страуструп пошёл на его использование в качестве основы, так как «в C есть свои проблемы, но их имел бы и разработанный с нуля язык, а проблемы C нам известны». Кроме того, это позволило быстро получить прототип компилятора (cfront), который лишь выполнял трансляцию добавленных синтаксических элементов в оригинальный язык C.
По мере разработки C++ в него были включены другие средства, которые перекрывали возможности конструкций C, в связи с чем неоднократно поднимался вопрос об отказе от совместимости языков путём удаления устаревших конструкций. Тем не менее, совместимость была сохранена из следующих соображений:
Новые возможности C++ включают объявления в виде выражений, преобразования типов в виде функций, операторы new
и delete
, тип bool
, ссылки, расширенное понятие константности, подставляемые функции, аргументы по умолчанию, переопределения, пространства имён, классы (включая и все связанные с классами возможности, такие как наследование, функции-члены, виртуальные функции, абстрактные классы и конструкторы), переопределения операторов, шаблоны, оператор ::
, обработку исключений, динамическую идентификацию и многое другое. Язык C++ также во многих случаях строже относится к проверке типов, чем C.
В C++ появились комментарии в виде двойной косой черты (//
), которые были в предшественнике C — языке BCPL.
Некоторые особенности C++ позднее были перенесены в C, например, ключевые слова const
и inline
, объявления в циклах for
и комментарии в стиле C++ (//
). В более поздних реализациях C также были представлены возможности, которых нет в C++, например макросы va_arg
и улучшенная работа с массивами-параметрами.
Несмотря на то, что большая часть кода C будет справедлива и для C++, C++ не является надмножеством C и не включает его в себя. Существует и такой верный для C код, который неверен для C++. Это отличает его от Objective C, ещё одного усовершенствования C для ООП, как раз являющегося надмножеством C.
Существуют и другие различия. Например, C++ не разрешает вызывать функцию main()
внутри программы, в то время как в C это действие правомерно. Кроме того, C++ более строг в некоторых вопросах; например, он не допускает неявное приведение типов между несвязанными типами указателей и не разрешает использовать функции, которые ещё не объявлены.
Более того, код, верный для обоих языков, может давать разные результаты в зависимости от того, компилятором какого языка он оттранслирован. Например, на большинстве платформ следующая программа печатает «С», если компилируется компилятором C, и «C++» — если компилятором C++. Так происходит из-за того, что символьные константы в C (например, 'a'
) имеют тип int
, а в C++ — тип char
, а размеры этих типов обычно различаются.
#include <stdio.h>
int main()
{
printf("%s\n", (sizeof('a') == sizeof(char)) ? "C++" : "C");
return 0;
}
По замечанию Страуструпа, «чем лучше вы знаете C, тем труднее вам будет избежать программирования на C++ в стиле C, теряя при этом потенциальные преимущества C++». В связи с этим он даёт следующий набор рекомендаций для программистов на C, чтобы в полной мере воспользоваться преимуществами C++:
#define
. Для объявления констант применять const
, групп констант (перечислений) — enum
, для прямого включения функций — inline
, для определения семейств функций или типов — template
.malloc()
[17] в пользу оператора new
, от realloc()
[18] — в пользу типа vector
. Более безопасным будет использование умных указателей, таких как shared_ptr
и unique_ptr
, доступных с одиннадцатой версии стандарта.string
и vector
из STL. Вообще не стремиться создавать собственные реализации того, что уже имеется в стандартной библиотеке.Текущий стандарт языка ISO/IEC 14882:2017 был опубликован в декабре 2017 года. Неофициально его обозначают как C++17. Следующая версия стандарта, запланированная на 2020 год, имеет неофициальное обозначение C++20.
По мнению автора языка Бьёрна Страуструпа[19][20][21], говоря о дальнейшем развитии и перспективах языка, можно выделить следующее:
constexpr
.auto
и описание decltype
.for (type &x: array) {...}
. Здесь тело цикла выполняется для каждого элемента коллекции array
, а x
в каждой итерации будет ссылаться на очередной элемент коллекции. В качестве коллекции может выступать C-массив или любой контейнер стандартной библиотеки, для которого определены итераторы begin
и end
.override
, который употребляется в объявлении метода, замещающего виртуальный метод родительского класса. Описание замещения с override
вызывает проверку на наличие в родительском классе замещаемого метода и на совпадение сигнатур методов.final
, как и в Java, запрещающий дальнейшее замещение помеченного им метода. Также final
может быть объявлен класс — в таком случае от него запрещено наследовать новые классы.nullptr
.>>
» воспринималась однозначно как операция побитового сдвига вправо, поэтому в записи вложенных шаблонных конструкций требовалось обязательно разделять знаки «больше» пробелами или переводами строк).Это пример программы Hello, world!, которая выводит сообщение в консоль, используя стандартную библиотеку, и завершается.
#include <iostream>
using namespace std;
int main()
{
cout << "Hello, world!" << endl;
return 0;
}
Современный C++ позволяет решать простым способом и более сложные задачи. Этот пример демонстрирует, кроме всего прочего, использование контейнеров стандартной библиотеки шаблонов (STL).
#include <iostream> // для использования std::cout
#include <vector> // содержит динамический массив
#include <map> // содержит тип данных словарь
#include <string>
int main()
{
// Импортируем все объявления в пространстве имён "std" в глобальное пространство имён.
using namespace std;
// Объявляем ассоциативный контейнер со строковыми ключами и данными в виде векторов строк.
map<string, vector<string> > items;
// Добавим в этот ассоциативный контейнер пару человек и дадим им несколько предметов.
items["Anya"].push_back("scarf");
items["Dmitry"].push_back("tickets");
items["Anya"].push_back("puppy");
// Переберём все объекты в контейнере
for(const auto& person : items) {
// person - это пара двух объектов: person.first - это его имя,
// person.second - это список его предметов (вектор строк)
cout << person.first << " is carrying " << person.second.size() << " items" << endl;
}
}
В этом примере для простоты импортируются все имена из пространства имён std. В настоящей же программе так делать не рекомендуется, так как можно столкнуться с коллизией имён. Язык позволяет импортировать отдельные объекты:
#include <vector>
int main()
{
using std::vector;
vector<int> my_vector;
}
В C++ (как и в C), если выполнение программы доходит до конца функции main()
, то это эквивалентно return 0;
. Это неверно для любой другой функции кроме main()
.
Известно несколько исследований, в которых была сделана попытка более или менее объективно сравнить несколько языков программирования, одним из которых является C++. В частности:
Язык Ада близок к C++ по набору возможностей и по сферам применения: это компилируемый структурный язык с Симула-подобным объектно-ориентированным дополнением (та же модель «Алгол с классами», что и в C++), статической типизацией, средствами обобщённого программирования, предназначенный для разработки крупных и сложных программных систем. В то же время он принципиально отличается по идеологии: в отличие от C++, Ада строилась на основе предварительно тщательно проработанных условий производителей сложного ПО с повышенными требованиями к надёжности, что наложило отпечаток на синтаксис и семантику языка.
Прямых сравнений эффективности кодирования на Аде и C++ немного. В упомянутой выше статье[22] решение модельной задачи на Аде привело к получению кода примерно на 30 % меньшего по объёму (в строках), чем на C++. Сравнение свойств самих языков приводится во многих источниках, например, в статье Джима Роджерса на AdaHome[28] содержится перечисление более 50 пунктов различий свойств этих языков, большая часть которых — в пользу Ады (больше возможностей, более гибкое поведение, меньше вероятность ошибок). Хотя многие утверждения сторонников Ады спорны, а часть из них явно устарела, в целом можно заключить:
select
). В C++ всё это реализуется только на уровне библиотек.В статье Стефена Цейгера из Rational Software Corporation[29], утверждается, что в целом разработка на Аде обходится на 60% дешевле, и приводит к получению кода, имеющего в 9 раз меньше дефектов, чем на Си. Хотя эти результаты не могут быть прямо перенесены на C++, но всё же представляют интерес с учётом того, что многие недостатки C++ унаследованы от Си.
Java не может считаться в полной мере заменой C++, она создана как безопасный язык с низким порогом вхождения для разработки прикладных пользовательских приложений с высокими показателями портируемости[30] и принципиально непригодна для некоторых типов приложений, которые разрабатываются на C++. Однако в пределах своей области Java составляет вполне реальную конкуренцию C++. В качестве преимуществ Java обычно называют:
В то же время использование сборщика мусора и виртуальной машины создают труднопреодолимые ограничения. Программы на Java, как правило, медленнее, требуют значительно больше памяти, к тому же виртуальная машина изолирует программу от операционной системы, делая невозможным низкоуровневое программирование.
Эмпирическое исследование[24] не обнаружило существенной разницы в скорости разработки на C++ и на Java. Исследование[26] также показало, что представление о существенной разнице в скорости программ на этих языках не всегда верно: в двух из трёх тестов скорость работы приложений на Java и C++ оказалась сравнима. В то же время Java лаконичнее — разница в объёме кода составила порядка 10-15 %.
Оригинальный Си продолжает развиваться, на нём разрабатываются многие масштабные проекты: он является основным языком разработки операционных систем, на нём написаны игровые движки многих динамических игр и большое число прикладных приложений. Ряд специалистов утверждает, что замена Си на C++ не повышает эффективность разработки, но приводит к ненужному усложнению проекта, снижению надёжности и увеличению затрат на сопровождение. В частности:
Нет убедительных данных о преимуществе C++ перед Си ни по производительности программистов, ни по свойствам программ. Хотя есть исследования[32], утверждающие, что программисты на Си тратят около 30-40% общего времени разработки (не считая отладки) на управление памятью, при сопоставлении общей производительности разработчиков[22] Си и C++ оказываются близки.
В низкоуровневом программировании значительная часть новых возможностей C++ оказывается неприменимой из-за увеличения накладных расходов: виртуальные функции требуют динамического вычисления реального адреса (RVA), шаблоны приводят к раздуванию кода и ухудшению возможностей оптимизации, библиотека времени исполнения (RTL) очень велика, а отказ от неё лишает большинства возможностей C++ (хотя бы из-за недоступности операций new
/delete
). В результате программисту придётся ограничиться функционалом, унаследованным от Си, что делает бессмысленным применение C++:
… единственный способ иметь хороший, эффективный, низкоуровневый и портируемый C++ сводится к тому, чтобы ограничиться всеми теми вещами, которые элементарно доступны в Си. А ограничение проекта рамками Си будет означать, что люди его не выкинут, и что будет доступно множество программистов, действительно хорошо понимающих низкоуровневые особенности и не отказывающихся от них из-за идиотской ерунды про «объектные модели».
… когда эффективность является первостепенным требованием, «преимущества» C++ будут огромной ошибкой.
В одном эксперименте[22] скриптовые и функциональные языки, в частности, Haskell, показали 2-3 кратный выигрыш во времени программирования и объёме кода по сравнению с программами на C++. С другой стороны, программы на C++ оказались во столько же раз быстрее. Авторы признают, что полученные ими данные не составляют репрезентативной выборки и воздерживаются от категоричных выводов.
В другом эксперименте[34] строгие функциональные языки (Standard ML, OCaml) показали общее ускорение разработки в 10 раз (в основном за счёт раннего выявления ошибок) при примерно равных показателях быстродействия (использовалось множество компиляторов в нескольких режимах).
В исследовании Лутца Прехельта[24] по результатам обработки около 80 решений, написанных добровольцами, получены, в частности, следующие выводы:
Содержимое этой статьи нуждается в чистке.
|