C ++ - C++

C ++
ISO C ++ Logo.svg
Логотип одобрен Стандартным C ++
Парадигмы Мультипарадигма : процедурная , функциональная , объектно-ориентированная , универсальная , модульная
Семья C
Разработано Бьярне Страуструп
Разработчик ISO / IEC JTC1 (Объединенный технический комитет 1) / SC22 (Подкомитет 22) / WG21 (Рабочая группа 21)
Впервые появился 1985 ; 36 лет назад ( 1985 )
Стабильный выпуск
C ++ 20 (ISO / IEC 14882: 2020) / 15 декабря 2020 г . ; 9 месяцев назад ( 2020-12-15 )
Предварительный выпуск
C ++ 23/18 июня 2021 г . ; 3 месяца назад ( 2021-06-18 )
Печатная дисциплина Статический , именительный падеж , частично предполагаемый
Операционные системы Кроссплатформенность
Расширения имени файла .C, .cc, .cpp, .cxx, .c ++ , .h, .H, .hh, .hpp, .hxx, .h ++
Веб-сайт isocpp .org
Основные реализации
GCC , LLVM Clang , Microsoft Visual C ++ , Embarcadero C ++ Builder , компилятор Intel C ++ , IBM XL C ++ , EDG
Под влиянием
Ада , АЛГОЛ 68 , C , CLU , ML , Mesa , Modula-2 , Simula , Smalltalk
Под влиянием
Ада 95 , C # , C99 , Chapel , Clojure , D , Java , JS ++ , Lua , Nim , Objective-C ++ , Perl , PHP , Python , Rust , Seed7

С ++ ( / ° сек я ° р а л ʌ сек р л ʌ с / ) является язык программирования общего назначения , созданный Бьярне Страуструп как расширение языка программирования С , или «C с классами ». Со временем язык значительно расширился, и современный C ++ теперь имеет объектно-ориентированные , универсальные и функциональные возможности в дополнение к средствам для низкоуровневого манипулирования памятью . Он почти всегда реализуется как компилируемый язык , и многие поставщики предоставляют компиляторы C ++ , включая Free Software Foundation , LLVM , Microsoft , Intel , Oracle и IBM , поэтому он доступен на многих платформах.

C ++ был разработан с ориентацией на системное программирование и встроенное программное обеспечение с ограниченными ресурсами и большие системы, с производительностью , эффективностью и гибкостью использования, как это подчеркивается в его конструкции. C ++ также оказался полезным во многих других контекстах, при этом ключевыми сильными сторонами являются программная инфраструктура и приложения с ограниченными ресурсами, включая настольные приложения , видеоигры , серверы (например, электронная коммерция , веб-поиск или базы данных ) и приложения, критичные к производительности ( например, телефонные переключатели или космические зонды ).

C ++ стандартизирован Международной организацией по стандартизации (ISO), последняя версия стандарта ратифицирована и опубликована ISO в декабре 2020 года как ISO / IEC 14882: 2020 (неофициально известный как C ++ 20 ). Язык программирования C ++ был первоначально стандартизирован в 1998 году как ISO / IEC 14882: 1998 , который затем был изменен стандартами C ++ 03 , C ++ 11 , C ++ 14 и C ++ 17 . Текущий стандарт C ++ 20 заменяет их новыми функциями и расширенной стандартной библиотекой . До первоначальной стандартизации в 1998 году C ++ был разработан датским компьютерным ученым Бьярном Страуструпом в Bell Labs с 1979 года как расширение языка C ; ему нужен был эффективный и гибкий язык, подобный C, который также обеспечивал высокоуровневые функции для организации программ. С 2012 года C ++ находится на трехлетнем графике выпуска с C ++ 23 в качестве следующего запланированного стандарта.

История

Бьярн Страуструп, создатель C ++, в своем офисе AT&T в Нью-Джерси c. 2000 г.

В 1979 году датский ученый-компьютерщик Бьярне Страуструп начал работу над "C с классами ", предшественник C ++. Мотивация к созданию нового языка возникла из опыта Страуструпа в программировании для его докторской диссертации. Страуструп обнаружил, что в Simula есть функции, которые были очень полезны для крупномасштабной разработки программного обеспечения, но язык был слишком медленным для Практическое использование, в то время как BCPL был быстрым, но слишком низкоуровневым, чтобы подходить для крупномасштабной разработки программного обеспечения. Когда Страуструп начал работать в AT&T Bell Labs , у него возникла проблема анализа ядра UNIX с точки зрения распределенных вычислений . Вспоминая свой докторский опыт, Страуструп намеревался улучшитьязык C с помощьюфункций, подобных Simula . C был выбран потому, что он был универсальным, быстрым, переносимым и широко используемым. Помимо C и влияния Simula, другие языки также повлияли на этот новый язык, включая ALGOL 68 , Ада , CLU и ML .

Первоначально "C с классами" Страуструпа добавлял возможности компилятору C, Cpre, включая классы , производные классы , строгую типизацию , встраивание и аргументы по умолчанию .

Викторина по функциям C ++ 11, проводимая в Париже в 2015 году

В 1982 году Страуструп начал разработку преемника C с классами, который он назвал «C ++» ( являющийся оператором приращения в C) после того, как перебрал несколько других имен. Были добавлены новые функции, в том числе виртуальные функции , перегрузка имени функции и оператора , ссылки , константы, безопасное для типов выделение памяти в свободном хранилище (новое / удаление), улучшенная проверка типов и однострочные комментарии в стиле BCPL с двумя косыми чертами ( ) . Кроме того, Страуструп разработал новый автономный компилятор для C ++, Cfront . ++//

В 1984 году Страуструп реализовал первую библиотеку потокового ввода / вывода. Идея предоставления оператора вывода, а не именованной функции вывода была предложена Дугом Макилроем (который ранее предлагал каналы Unix ).

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

В 1989 году был выпущен C ++ 2.0, а в 1991 году - обновленное второе издание языка программирования C ++ . Новые функции 2.0 включали множественное наследование, абстрактные классы, статические функции-члены, константные функции- члены и защищенные члены. В 1990 году было опубликовано Справочное руководство по C ++ с комментариями . Эта работа стала основой будущего стандарта. Более поздние дополнения к функциям включали шаблоны , исключения , пространства имен , новые приведения типов и логический тип .

В 1998 году был выпущен C ++ 98, стандартизирующий язык, а в 2003 году было выпущено небольшое обновление ( C ++ 03 ).

После C ++ 98 C ++ развивался относительно медленно, пока в 2011 году не был выпущен стандарт C ++ 11 , добавивший множество новых функций, дальнейшее расширение стандартной библиотеки и предоставившие больше возможностей программистам на C ++. После небольшого обновления C ++ 14, выпущенного в декабре 2014 г., в C ++ 17 были внесены различные новые дополнения . После завершения в феврале 2020 года черновик стандарта C ++ 20 был утвержден 4 сентября 2020 года и официально опубликован 15 декабря 2020 года.

3 января 2018 года Страуструп был объявлен лауреатом Премии Чарльза Старка Дрейпера в области инженерии за 2018 год «за концептуализацию и разработку языка программирования C ++».

По состоянию на 2021 год C ++ занял четвертое место в индексе TIOBE , показателе популярности языков программирования, после C , Java и Python .

Этимология

Согласно Страуструпу, «название означает эволюционный характер изменений от C». Это название приписывают Рику Mascitti (середина 1983) и впервые был использован в декабре 1983 года Когда Mascitti была поставлена под сомнение в неофициальном порядке в 1992 году о наименовании, он указал , что он был дан в неискренний духе. Название происходит от языка C оператора (который увеличивает на величину от в переменном ) и общее именование использования «+» , чтобы указать , расширенную компьютерную программу. ++

В период разработки C ++ этот язык назывался «новый C» и «C с классами» до того, как получил свое окончательное название.

Философия

На протяжении всей жизни C ++ его развитие и эволюция руководствовались рядом принципов:

  • Он должен быть вызван реальными проблемами, и его функции должны быть незамедлительно полезны в реальных программах.
  • Каждая функция должна быть реализована (достаточно очевидным способом).
  • Программисты должны иметь право выбирать свой собственный стиль программирования, и этот стиль должен полностью поддерживаться C ++.
  • Разрешение полезной функции важнее, чем предотвращение всех возможных злоупотреблений C ++.
  • Он должен предоставлять возможности для организации программ в отдельные, четко определенные части и предоставлять возможности для объединения отдельно разработанных частей.
  • Никаких неявных нарушений системы типов (но допускаются явные нарушения, то есть явно запрошенные программистом).
  • Типы, созданные пользователями, должны иметь такую ​​же поддержку и производительность, как и встроенные типы.
  • Неиспользуемые функции не должны отрицательно влиять на созданные исполняемые файлы (например, снижать производительность).
  • Ниже C ++ не должно быть языка (кроме языка ассемблера ).
  • C ++ должен работать вместе с другими существующими языками программирования , а не создавать собственную отдельную и несовместимую среду программирования .
  • Если намерение программиста неизвестно, разрешите программисту указать его, предоставив ручное управление.

Стандартизация

Сцена во время заседания комитета по стандартам C ++ в Стокгольме в 1996 г.
Стандарты C ++
Год Стандарт C ++ Неофициальное имя
1998 г. ИСО / МЭК 14882: 1998 C ++ 98
2003 г. ИСО / МЭК 14882: 2003 С ++ 03
2011 г. ИСО / МЭК 14882: 2011 С ++ 11 , С ++ 0x
2014 г. ИСО / МЭК 14882: 2014 C ++ 14 , C ++ 1y
2017 г. ИСО / МЭК 14882: 2017 С ++ 17 , С ++ 1z
2020 г. ИСО / МЭК 14882: 2020 C ++ 20 , C ++ 2a

C ++ стандартизирован рабочей группой ISO, известной как JTC1 / SC22 / WG21 . На данный момент он опубликовал шесть редакций стандарта C ++ и в настоящее время работает над следующей версией, C ++ 23 .

В 1998 году рабочая группа ISO впервые стандартизировала C ++ как ISO / IEC 14882: 1998 , который неофициально известен как C ++ 98 . В 2003 году он опубликовал новую версию стандарта C ++ под названием ISO / IEC 14882: 2003 , в которой исправлены проблемы, выявленные в C ++ 98.

Следующая крупная версия стандарта неофициально называлась «C ++ 0x», но была выпущена только в 2011 году. C ++ 11 (14882: 2011) включал множество дополнений как к основному языку, так и к стандартной библиотеке.

В 2014 году C ++ 14 (также известный как C ++ 1y) был выпущен как небольшое расширение для C ++ 11 , в котором в основном исправлены ошибки и небольшие улучшения. Проект международных стандартных процедур голосования завершился в середине августа 2014 года.

После C ++ 14 основная версия C ++ 17 , неофициально известная как C ++ 1z, была завершена Комитетом ISO по C ++ в середине июля 2017 года и была одобрена и опубликована в декабре 2017 года.

В рамках процесса стандартизации ISO также публикует технические отчеты и спецификации :

  • ISO / IEC TR 18015: 2006 об использовании C ++ во встроенных системах и о влиянии на производительность языка C ++ и функций библиотеки,
  • ISO / IEC TR 19768: 2007 (также известный как Технический отчет C ++ 1 ) о расширениях библиотек, в основном интегрированных в C ++ 11 ,
  • ISO / IEC TR 29124: 2010 по специальным математическим функциям, интегрированный в C ++ 17
  • ISO / IEC TR 24733: 2011 о десятичной арифметике с плавающей запятой ,
  • ISO / IEC TS 18822: 2015 о стандартной библиотеке файловой системы, интегрированной в C ++ 17
  • ISO / IEC TS 19570: 2015 о параллельных версиях алгоритмов стандартной библиотеки, интегрированных в C ++ 17
  • ISO / IEC TS 19841: 2015 о программной транзакционной памяти ,
  • ISO / IEC TS 19568: 2015 о новом наборе расширений библиотеки, некоторые из которых уже интегрированы в C ++ 17 ,
  • ISO / IEC TS 19217: 2015 о концепциях C ++ , интегрированных в C ++ 20
  • ISO / IEC TS 19571: 2016 о расширениях библиотеки для параллелизма, некоторые из которых уже интегрированы в C ++ 20.
  • ISO / IEC TS 19568: 2017 о новом наборе универсальных расширений библиотеки
  • ISO / IEC TS 21425: 2017 о расширениях библиотеки для диапазонов, интегрированных в C ++ 20
  • ISO / IEC TS 22277: 2017 по сопрограммам, интегрированным в C ++ 20
  • ISO / IEC TS 19216: 2018 о сетевой библиотеке
  • ISO / IEC TS 21544: 2018 по модулям, интегрированным в C ++ 20
  • ISO / IEC TS 19570: 2018 о новом наборе расширений библиотеки для параллелизма

Другие технические характеристики, включая статическое отражение, находятся в разработке и ожидают утверждения.

Язык

В языке C ++ есть два основных компонента: прямое отображение аппаратных функций, предоставляемых в основном подмножеством C, и абстракции с нулевыми накладными расходами, основанные на этих отображениях. Страуструп описывает C ++ как «легкий язык программирования абстракций [разработанный] для создания и использования эффективных и элегантных абстракций»; и «предложение аппаратного доступа и абстракции - основа C ++. Эффективное выполнение - вот что отличает его от других языков».

C ++ наследует большинство из синтаксиса языка C . Ниже приводится версия программы Hello world Бьярна Страуструпа, которая использует средство потока стандартной библиотеки C ++ для вывода сообщения на стандартный вывод :

#include <iostream>

int main()
{
    std::cout << "Hello, world!\n";
}

Хранилище объектов

Как и в C, C ++ поддерживает четыре типа управления памятью : статические объекты продолжительности хранения, объекты продолжительности хранения потоков, объекты автоматической продолжительности хранения и объекты продолжительности динамической памяти.

Объекты длительности статического хранения

Объекты длительности статического хранения создаются до main()входа (см. Исключения ниже) и уничтожаются в обратном порядке создания после main()выхода. Точный порядок создания не определен стандартом (хотя есть некоторые правила, определенные ниже), чтобы дать реализациям некоторую свободу в том, как организовать их реализацию. Говоря более формально, объекты этого типа имеют продолжительность жизни, которая «должна длиться в течение всей программы».

Объекты длительности статического хранения инициализируются в два этапа. Сначала выполняется «статическая инициализация», и только после выполнения всей статической инициализации выполняется «динамическая инициализация». При статической инициализации все объекты сначала инициализируются нулями; после этого все объекты, которые имеют постоянную фазу инициализации, инициализируются постоянным выражением (т.е. переменные инициализируются литералом или constexpr). Хотя это не указано в стандарте, фаза статической инициализации может быть завершена во время компиляции и сохранена в разделе данных исполняемого файла. Динамическая инициализация включает в себя всю инициализацию объекта, выполняемую с помощью конструктора или вызова функции (если функция не отмечена значком constexprв C ++ 11). Порядок динамической инициализации определяется как порядок объявления в модуле компиляции (то есть в том же файле). Не дается никаких гарантий относительно порядка инициализации между единицами компиляции.

Объекты продолжительности хранения потока

Переменные этого типа очень похожи на статические объекты продолжительности хранения. Основное отличие заключается в том, что время создания - непосредственно перед созданием потока, а уничтожение выполняется после того, как поток был присоединен.

Объекты автоматической продолжительности хранения

Наиболее распространенные типы переменных в C ++ - это локальные переменные внутри функции или блока и временные переменные. Общей чертой автоматических переменных является то, что их время жизни ограничено областью действия переменной. Они создаются и потенциально инициализируются в точке объявления (подробности см. Ниже) и уничтожаются в порядке, обратном созданию, когда область видимости остается. Это реализуется путем выделения в стеке .

Локальные переменные создаются, когда точка выполнения проходит точку объявления. Если у переменной есть конструктор или инициализатор, он используется для определения начального состояния объекта. Локальные переменные уничтожаются, когда закрывается локальный блок или функция, в которой они объявлены. Деструкторы C ++ для локальных переменных вызываются в конце жизненного цикла объекта, обеспечивая дисциплину автоматического управления ресурсами, называемую RAII , которая широко используется в C ++.

Переменные-члены создаются при создании родительского объекта. Члены массива инициализируются от 0 до последнего члена массива по порядку. Переменные-члены уничтожаются, когда родительский объект уничтожается в порядке, обратном созданию. т.е. если родительский объект является «автоматическим объектом», он будет уничтожен, когда выйдет за пределы области видимости, что приведет к уничтожению всех его членов.

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

Объекты продолжительности динамического хранения

Эти объекты имеют динамический срок жизни и могут быть созданы непосредственно с вызовом и явно уничтожены с помощью вызова . C ++ также поддерживает и , начиная с C, но они несовместимы с и . Использование возвращает адрес в выделенную память. Руководящие принципы C ++ Core не рекомендуют использовать прямое использование для создания динамических объектов в пользу интеллектуальных указателей для единого владения и для множественного владения с подсчетом ссылок, которые были введены в C ++ 11. newdeletemallocfreenewdeletenewnewmake_unique<T>make_shared<T>

Шаблоны

Шаблоны C ++ обеспечивают универсальное программирование . C ++ поддерживает шаблоны функций, классов, псевдонимов и переменных. Шаблоны могут быть параметризованы типами, константами времени компиляции и другими шаблонами. Шаблоны реализуются путем создания экземпляров во время компиляции. Чтобы создать экземпляр шаблона, компиляторы заменяют определенные аргументы параметрами шаблона, чтобы сгенерировать конкретную функцию или экземпляр класса. Некоторые замены невозможны; они устраняются политикой разрешения перегрузки, описанной фразой « Ошибка замены не является ошибкой » (SFINAE). Шаблоны - это мощный инструмент, который можно использовать для общего программирования , метапрограммирования шаблонов и оптимизации кода, но эта возможность требует затрат. Использование шаблона может увеличить размер кода, потому что каждый экземпляр шаблона создает копию кода шаблона: по одной для каждого набора аргументов шаблона, однако это такой же или меньший объем кода, который был бы сгенерирован, если бы код был написан вручную. Это контрастирует с универсальными шаблонами времени выполнения, встречающимися в других языках (например, Java ), где во время компиляции тип стирается, а одно тело шаблона сохраняется.

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

Кроме того, шаблоны - это механизм времени компиляции в C ++, который является полным по Тьюрингу , что означает, что любое вычисление, выражаемое компьютерной программой, может быть вычислено в той или иной форме с помощью метапрограммы шаблона до времени выполнения.

Таким образом, шаблон - это параметризованная функция или класс времени компиляции, написанный без знания конкретных аргументов, используемых для его создания. После создания экземпляра результирующий код эквивалентен коду, написанному специально для переданных аргументов. Таким образом, шаблоны предоставляют способ отделить общие, широко применимые аспекты функций и классов (закодированные в шаблонах) от конкретных аспектов (закодированных в параметрах шаблона) без ущерба для производительности из-за абстракции.

Объекты

C ++ вводит в C. функции объектно-ориентированного программирования (ООП). Он предлагает классы , которые предоставляют четыре функции, обычно присутствующие в ООП (и некоторых не-ООП) языках: абстракция , инкапсуляция , наследование и полиморфизм . Отличительной особенностью классов C ++ по сравнению с классами других языков программирования является поддержка детерминированных деструкторов , которые, в свою очередь, обеспечивают поддержку концепции Resource Acquisition is Initialization (RAII).

Инкапсуляция

Инкапсуляция - это сокрытие информации, чтобы гарантировать, что структуры данных и операторы используются по назначению, и сделать модель использования более очевидной для разработчика. C ++ предоставляет возможность определять классы и функции в качестве основных механизмов инкапсуляции. Внутри класса члены могут быть объявлены как общедоступные, защищенные или частные, чтобы явно обеспечить инкапсуляцию. Открытый член класса доступен любой функции. Частный член доступен только для функций, которые являются членами этого класса, а также для функций и классов, явно предоставленных классом разрешения на доступ («друзья»). Защищенный член доступен членам классов, которые наследуются от класса, в дополнение к самому классу и его друзьям.

Объектно-ориентированный принцип обеспечивает инкапсуляцию всех и только функций, которые обращаются к внутреннему представлению типа. C ++ поддерживает этот принцип с помощью функций-членов и дружественных функций, но не обеспечивает его соблюдение. Программисты могут объявить часть или все представление типа общедоступным, и им разрешено сделать общедоступные объекты не частью представления типа. Следовательно, C ++ поддерживает не только объектно-ориентированное программирование, но и другие парадигмы декомпозиции, такие как модульное программирование .

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

Наследование

Наследование позволяет одному типу данных приобретать свойства других типов данных. Наследование от базового класса может быть объявлено как общедоступное, защищенное или частное. Этот спецификатор доступа определяет, могут ли несвязанные и производные классы получить доступ к унаследованным общедоступным и защищенным членам базового класса. Только публичное наследование соответствует тому, что обычно подразумевается под «наследованием». Две другие формы используются гораздо реже. Если спецификатор доступа опущен, «класс» наследуется частным образом, а «структура» - публично. Базовые классы могут быть объявлены виртуальными; это называется виртуальным наследованием . Виртуальное наследование гарантирует, что в графе наследования существует только один экземпляр базового класса, что позволяет избежать некоторых проблем неоднозначности множественного наследования.

Множественное наследование - это функция C ++, которая позволяет классу быть производным от более чем одного базового класса; это позволяет создавать более сложные отношения наследования. Например, класс «Летающий кот» может наследовать как от «Кошка», так и от «Летающего млекопитающего». Некоторые другие языки, такие как C # или Java , достигают чего-то похожего (хотя и более ограниченного), разрешая наследование нескольких интерфейсов , ограничивая количество базовых классов одним (интерфейсы, в отличие от классов, предоставляют только объявления функций-членов, без реализации или члена данные). Интерфейс, как в C # и Java, может быть определен в C ++ как класс, содержащий только чистые виртуальные функции, часто известный как абстрактный базовый класс или «ABC». Функции-члены такого абстрактного базового класса обычно явно определяются в производном классе, а не наследуются неявно. Виртуальное наследование C ++ демонстрирует функцию разрешения неоднозначности, называемую доминированием .

Операторы и перегрузка операторов

Операторы, которые нельзя перегружать
Оператор Условное обозначение
Оператор разрешения области видимости ::
Условный оператор ?:
оператор точки .
Оператор выбора члена .*
« SizeOf оператор» sizeof
« TypeId оператор» typeid

C ++ предоставляет более 35 операторов, охватывающих базовую арифметику, манипуляции с битами, косвенное обращение, сравнения, логические операции и другие. Почти все операторы могут быть перегружены для определяемых пользователем типов, за некоторыми заметными исключениями, такими как доступ к члену ( .и .*), а также условный оператор. Богатый набор перегружаемых операторов играет центральную роль в том, чтобы пользовательские типы в C ++ казались встроенными.

Перегружаемые операторы также являются неотъемлемой частью многих передовых методов программирования на C ++, таких как интеллектуальные указатели . Перегрузка оператора не меняет приоритета вычислений, связанных с оператором, и не меняет количество операндов, которые использует оператор (однако любой операнд может игнорироваться оператором, хотя он будет оценен перед выполнением). Перегруженные операторы " &&" и " ||" теряют свойство оценки короткого замыкания .

Полиморфизм

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

C ++ поддерживает несколько видов статических (разрешенных во время компиляции ) и динамических (разрешенных во время выполнения ) полиморфизмов , поддерживаемых функциями языка, описанными выше. Полиморфизм во время компиляции не позволяет принимать определенные решения во время выполнения , в то время как полиморфизм во время выполнения обычно влечет за собой снижение производительности.

Статический полиморфизм

Перегрузка функций позволяет программам объявлять несколько функций с одним и тем же именем, но с разными аргументами (например, специальный полиморфизм ). Функции различаются по количеству или типу их формальных параметров . Таким образом, одно и то же имя функции может относиться к разным функциям в зависимости от контекста, в котором оно используется. Тип, возвращаемый функцией, не используется для различения перегруженных функций, и разные возвращаемые типы приведут к сообщению об ошибке времени компиляции.

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

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

Динамический полиморфизм

Наследование

Указатели переменных и ссылки на тип базового класса в C ++ также могут ссылаться на объекты любых производных классов этого типа. Это позволяет массивам и другим видам контейнеров содержать указатели на объекты разных типов (ссылки не могут храниться непосредственно в контейнерах). Это обеспечивает динамический (во время выполнения) полиморфизм, при котором указанные объекты могут вести себя по-разному, в зависимости от их (фактических, производных) типов.

C ++ также предоставляет оператор, который позволяет коду безопасно попытаться преобразовать объект через базовую ссылку / указатель в более производный тип: понижающее преобразование . Попытка необходимо , так как часто один не знает , какой производный тип ссылается. ( Апкастинг , преобразование в более общий тип, всегда можно проверить / выполнить во время компиляции с помощью , поскольку наследственные классы указаны в интерфейсе производного класса, видимого для всех вызывающих.) Полагается на информацию о типе времени выполнения (RTTI), метаданные в программе, позволяющие различать типы и их отношения. Если a на указатель не работает, результатом является константа, тогда как если адресатом является ссылка (которая не может быть нулевой), приведение выдает исключение. Объекты, которые, как известно, принадлежат к определенному производному типу, могут быть преобразованы в него , минуя RTTI и безопасную проверку типов во время выполнения , поэтому это следует использовать только в том случае, если программист очень уверен, что приведение является и всегда будет действительным. dynamic_caststatic_castdynamic_castdynamic_castnullptrstatic_castdynamic_cast

Виртуальные функции-члены

Обычно, когда функция в производном классе переопределяет функцию в базовом классе, функция для вызова определяется типом объекта. Данная функция переопределяется, если не существует разницы в количестве или типе параметров между двумя или более определениями этой функции. Следовательно, во время компиляции может оказаться невозможным определить тип объекта и, следовательно, правильную функцию для вызова, учитывая только указатель базового класса; поэтому решение откладывается до времени выполнения. Это называется динамической отправкой . Виртуальные функции или методы- члены позволяют вызывать наиболее конкретную реализацию функции в соответствии с фактическим типом времени выполнения объекта. В реализациях C ++ это обычно делается с помощью таблиц виртуальных функций . Если тип объекта известен, этого можно избежать, добавив полностью определенное имя класса перед вызовом функции, но в целом вызовы виртуальных функций разрешаются во время выполнения.

Помимо стандартных функций-членов, перегрузки операторов и деструкторы могут быть виртуальными. Неточное правило, основанное на практическом опыте, гласит, что если какая-либо функция в классе является виртуальной, деструктор также должен быть. Поскольку тип объекта при его создании известен во время компиляции, конструкторы и конструкторы копирования расширений не могут быть виртуальными. Тем не менее может возникнуть ситуация, когда необходимо создать копию объекта, когда указатель на производный объект передается как указатель на базовый объект. В таком случае обычным решением является создание (или аналогичной) виртуальной функции, которая создает и возвращает копию производного класса при вызове. clone()

Функцию-член также можно сделать «чистой виртуальной», добавив ее после закрывающей круглой скобки и перед точкой с запятой. Класс, содержащий чистую виртуальную функцию, называется абстрактным классом . Объекты нельзя создавать из абстрактного класса; они могут быть получены только из. Любой производный класс наследует виртуальную функцию как чистую и должен предоставлять не чистое определение ее (и всех других чистых виртуальных функций) до того, как объекты производного класса могут быть созданы. Программа, которая пытается создать объект класса с чистой виртуальной функцией-членом или унаследованной чистой виртуальной функцией-членом, плохо сформирована. = 0

Лямбда-выражения

C ++ обеспечивает поддержку анонимных функций , также известных как лямбда-выражения , в следующей форме:

[capture](parameters) -> return_type { function_body }

Начиная с C ++ 20, вы можете писать параметры шаблона без ключевого слова : template

[capture]<template_parameters>(parameters) -> return_type { function_body }

Если лямбда не принимает параметров, () можно опустить, то есть

[capture] -> return_type { function_body }

Кроме того, тип возвращаемого значения лямбда-выражения может быть автоматически выведен, если это возможно, например:

[](int x, int y) { return x + y; } // inferred
[](int x, int y) -> int { return x + y; } // explicit

Список поддерживает определение замыканий . Такие лямбда-выражения определены в стандарте как синтаксический сахар для безымянного объекта функции . [capture]

Обработка исключений

Обработка исключений используется для сообщения о существовании проблемы или ошибки во время выполнения, от того места, где она была обнаружена, до того, где проблема может быть обработана. Это позволяет делать это единообразно и отдельно от основного кода, обнаруживая при этом все ошибки. В случае возникновения ошибки генерируется (вызывается) исключение, которое затем перехватывается ближайшим подходящим обработчиком исключения. Исключение вызывает выход из текущей области видимости, а также из каждой внешней области (распространения) до тех пор, пока не будет найден подходящий обработчик, вызывая, в свою очередь, деструкторы любых объектов в этих завершенных областях. При этом исключение представлено в виде объекта, несущего данные об обнаруженной проблеме.

Некоторые руководства по стилю C ++, такие как Google, LLVM и Qt, запрещают использование исключений.

Код, вызывающий исключение, помещается внутри блока. Исключения обрабатываются в отдельных блоках (обработчиках); у каждого блока может быть несколько обработчиков исключений, как это видно в примере ниже. trycatchtry

#include <iostream>
#include <vector>
#include <stdexcept>

int main() {
    try {
        std::vector<int> vec{3, 4, 3, 1};
        int i{vec.at(4)}; // Throws an exception, std::out_of_range (indexing for vec is from 0-3 not 1-4)
    }
    // An exception handler, catches std::out_of_range, which is thrown by vec.at(4)
    catch (std::out_of_range &e) {
        std::cerr << "Accessing a non-existent element: " << e.what() << '\n';
    }
    // To catch any other standard library exceptions (they derive from std::exception)
    catch (std::exception &e) {
        std::cerr << "Exception thrown: " << e.what() << '\n';
    }
    // Catch any unrecognised exceptions (i.e. those which don't derive from std::exception)
    catch (...) {
        std::cerr << "Some fatal error\n";
    }
}

Также можно целенаправленно вызывать исключения, используя ключевое слово; эти исключения обрабатываются обычным образом. В некоторых случаях исключения нельзя использовать по техническим причинам. Одним из таких примеров является критический компонент встроенной системы, где каждая операция должна быть гарантированно завершена в течение определенного периода времени. Это не может быть определено с помощью исключений, поскольку не существует инструментов для определения максимального времени, необходимого для обработки исключения. throw

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

Стандартная библиотека

Проект стандарта «Рабочий документ», утвержденный как C ++ 98; половина его размера была посвящена стандартной библиотеке C ++.

C ++ стандарт состоит из двух частей: ядра языка и стандартной библиотеки. Программисты на C ++ ожидают последнего от каждой крупной реализации C ++; он включает агрегированные типы ( векторы , списки, карты, наборы, очереди, стеки, массивы, кортежи), алгоритмы (find, for_each , binary_search , random_shuffle и т. д.), средства ввода / вывода ( iostream , для чтения и записи в консоль и файлы), библиотека файловой системы, поддержка локализации, интеллектуальные указатели для автоматического управления памятью, поддержка регулярных выражений , многопоточная библиотека, поддержка атомики (позволяющая читать или записывать переменную не более чем одним потоком за раз без каких-либо внешних синхронизация), утилиты времени (измерение, получение текущего времени и т. д.), система преобразования отчетов об ошибках, не использующих исключения C ++, в исключения C ++, генератор случайных чисел и слегка измененная версия стандартной библиотеки C (чтобы сделать соответствует системе типов C ++).

Большая часть библиотеки C ++ основана на стандартной библиотеке шаблонов (STL). К полезным инструментам, предоставляемым STL, относятся контейнеры в виде коллекций объектов (таких как векторы и списки ), итераторы , обеспечивающие доступ к контейнерам в виде массивов, и алгоритмы , выполняющие такие операции, как поиск и сортировка.

Кроме того, предоставляются (мульти) карты ( ассоциативные массивы ) и (мульти) наборы, каждый из которых экспортирует совместимые интерфейсы. Следовательно, с помощью шаблонов можно писать общие алгоритмы, которые работают с любым контейнером или с любой последовательностью, определенной итераторами. Как и в C, в особенности о библиотеке доступны с помощью #include директивы , чтобы включить стандартный заголовок . ++ Стандартная библиотека C обеспечивает 105 стандартные заголовки, из которых 27 являются устаревшими.

Стандарт включает STL, который изначально был разработан Александром Степановым , который много лет экспериментировал с универсальными алгоритмами и контейнерами. Когда он начал с C ++, он наконец нашел язык, на котором можно было создавать общие алгоритмы (например, сортировка STL), которые работают даже лучше, чем, например, стандартная библиотека C qsort, благодаря функциям C ++, таким как использование встраивания и компиляции. привязка времени вместо указателей функций. Стандарт не называет его «STL», поскольку это просто часть стандартной библиотеки, но этот термин все еще широко используется, чтобы отличить его от остальной части стандартной библиотеки (потоки ввода / вывода, интернационализация, диагностика, подмножество библиотеки C и т. д.).

Большинство компиляторов C ++ и все основные из них предоставляют соответствующую стандартам реализацию стандартной библиотеки C ++.

Основные принципы C ++

Основные принципы C ++ - это инициатива, возглавляемая Бьярном Страуструпом, изобретателем C ++, и Хербом Саттером, организатором и председателем рабочей группы C ++ ISO, чтобы помочь программистам писать «современный C ++» с использованием передовых методов для языковых стандартов C + +14 и новее, а также чтобы помочь разработчикам компиляторов и инструментов статической проверки создавать правила для выявления плохих практик программирования.

Основная цель состоит в том, чтобы эффективно и последовательно писать на C ++, безопасном для типов и ресурсов.

Основные принципы были объявлены во вступительной речи на конференции CPPCon 2015.

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

Совместимость

Чтобы предоставить поставщикам компиляторов большую свободу, комитет по стандартам C ++ решил не диктовать реализацию изменения имен , обработки исключений и других специфичных для реализации функций. Обратной стороной этого решения является несовместимость объектного кода, созданного разными компиляторами . Однако были попытки стандартизировать компиляторы для конкретных машин или операционных систем (например, C ++ ABI), хотя сейчас от них, похоже, в значительной степени отказались.

С C

C ++ часто считается надмножеством C, но это не совсем так. Большую часть кода C можно легко заставить правильно скомпилировать в C ++, но есть несколько отличий, из-за которых некоторый допустимый код C становится недопустимым или ведет себя иначе в C ++. Например, C допускает неявное преобразование из в другие типы указателей, а C ++ - нет (по соображениям безопасности типов). Кроме того, C ++ определяет много новых ключевых слов, таких как и , которые могут использоваться в качестве идентификаторов (например, имен переменных) в программе на языке C. void*newclass

Некоторые несовместимости были устранены в версии 1999 года стандарта C ( C99 ), который теперь поддерживает такие функции C ++, как строковые комментарии ( //) и объявления, смешанные с кодом. С другой стороны, C99 представил ряд новых функций, которые не поддерживал C ++, которые были несовместимы или избыточны в C ++, например массивы переменной длины , собственные типы комплексных чисел (однако класс в стандартной библиотеке C ++ предоставляет аналогичные функции. , хотя и несовместим с кодом), назначенные инициализаторы, составные литералы и ключевое слово. Некоторые из представленных в C99 функций были включены в следующую версию стандарта C ++, C ++ 11 (из тех, которые не были избыточными). Однако стандарт C ++ 11 вводит новые несовместимости, такие как запрет на присвоение строкового литерала символьному указателю, который остается действительным C. std::complexrestrict

Чтобы смешивать код C и C ++, любое объявление или определение функции, которое должно вызываться / использоваться как в C, так и в C ++, должно быть объявлено со связью C путем помещения его в блок. Такая функция может не полагаться на возможности, зависящие от искажения имени (т. Е. От перегрузки функции). extern "C" {/*...*/}

Критика

Несмотря на широкое распространение, некоторые известные программисты критиковали язык C ++, в том числе Линус Торвальдс , Ричард Столлман , Джошуа Блох , Кен Томпсон и Дональд Кнут .

Одним из наиболее часто критикуемых моментов C ++ является его воспринимаемая сложность как языка, с критикой, что большое количество неортогональных функций на практике требует ограничения кода подмножеством C ++, тем самым избегая преимуществ читабельности общего стиля и идиом. . Как выразился Джошуа Блох :

Я думаю, что C ++ значительно превзошел свой порог сложности, и тем не менее, его программирует множество людей. Но что вы делаете, так это вынуждаете людей разделять это на части. Так что почти каждый известный мне магазин, использующий C ++, говорит: «Да, мы используем C ++, но мы не выполняем наследование с множественными реализациями и не используем перегрузку операторов». Есть просто набор функций, которые вы не собираетесь использовать, потому что сложность результирующего кода слишком высока. И я не думаю, что это хорошо, когда вам нужно начинать это делать. Вы теряете эту переносимость программиста, когда каждый может читайте чужой код, что, на мой взгляд, очень хорошо.

Дональд Кнут (1993, комментируя предварительно стандартизованный C ++), который сказал об Эдсгере Дейкстре, что «думать о программировании на C ++» «сделало бы его физически больным»:

Проблема, с которой я столкнулся сегодня с ними, заключается в том, что ... C ++ слишком сложен. На данный момент для меня невозможно написать переносимый код, который, как я полагаю, работал бы на множестве различных систем, если я не избегаю всех экзотических функций. Всякий раз, когда у разработчиков языка C ++ возникали две конкурирующие идеи относительно того, как им решить какую-либо проблему, они говорили: «Хорошо, мы сделаем их обе». Так что язык на мой вкус слишком барочный.

Кен Томпсон , который был коллегой Страуструпа в Bell Labs, дает свою оценку:

В этом, безусловно, есть свои плюсы. Но по большому счету я считаю, что это плохой язык. Многие вещи он делает наполовину хорошо, и это просто куча взаимоисключающих идей. Все, кого я знаю, будь то личные или корпоративные, выбирают подмножество, и эти подмножества разные. Так что это не лучший язык для переноса алгоритма - сказать: «Я написал его; вот, возьми». Он слишком большой, слишком сложный. И это, очевидно, построено комитетом . Страуструп годами, годами и годами проводил кампанию, выходящую за рамки любого технического вклада, который он внес в язык, чтобы добиться его принятия и использования. И он вроде как руководил всеми комитетами по стандартам с кнутом и стулом. И он никому не сказал «нет». Он вложил все функции на этом языке, которые когда-либо существовали. Он не был чисто спроектирован - это был просто союз всего, что произошло. И я думаю, что он сильно пострадал от этого.

Однако Брайан Керниган , также коллега из Bell Labs, оспаривает эту оценку:

C ++ оказал огромное влияние. ... Многие люди говорят, что C ++ слишком велик, слишком сложен и т. Д. И т. Д., Но на самом деле это очень мощный язык, и почти все, что там есть, существует по действительно веской причине: это не кто-то случайно изобретает , на самом деле это люди, пытающиеся решить проблемы реального мира. Многие программы, которые мы сегодня принимаем как должное и которые мы просто используем, являются программами на C ++.

Сам Страуструп отмечает, что семантика C ++ намного чище, чем его синтаксис: «внутри C ++ есть гораздо меньший и более чистый язык, изо всех сил пытающийся выбраться».

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

Смотрите также

использованная литература

дальнейшее чтение

внешние ссылки