Programmers вики
Advertisement


C++
Семантика:

мультипарадигмальный: объектно-ориентированное, обобщённое, процедурное, метапрограммирование

Тип исполнения:

компилируемый

Появился в:

1983 г.

Автор(ы):


Бьёрн Страуструп

Расширение файлов:

.c++ .cpp .cxx .cc .h++ .hpp .hxx .hh .h

Типизация данных:

статическая

Основные реализации:


GNU C++, Microsoft Visual C++, Intel C++ compiler, Comeau C/C++, Embarcadero (Borland) C++ Builder, Watcom C++ compiler, Digital Mars C++, Oracle Solaris Studio C++ compiler, Turbo C++

Диалекты:

ISO/IEC 14882 C++

C++ (произносится «си плюс плюс»[1]) — компилируемый статически типизированный язык программирования общего назначения. Поддерживая разные парадигмы программирования, сочетает свойства как высокоуровневых, так и низкоуровневых языков[2]. В сравнении с его предшественником— языком C, — наибольшее внимание уделено поддержке объектно-ориентированного и обобщённого программирования.[1] Название «C++» происходит от языка C, в котором унарный оператор ++ обозначает инкремент переменной.

Являясь одним из самых популярных языков программирования[3][4], C++ широко используется для разработки программного обеспечения. Область его применения включает операционные системы, прикладные программы, драйверы устройств, приложения для встраиваемых систем, высокопроизводительные серверы, а также развлекательные приложения, например, видеоигры. Существует несколько реализаций языка, как бесплатных, так и коммерческих. Их производят GNU Project, Microsoft, Intel и Embarcadero (Borland). C++ оказал огромное влияние на другие языки программирования, в первую очередь на C# и Java.

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

История[]

Язык возник в начале 1980-х годов, когда сотрудник фирмы Bell Laboratories Бьёрн Страуструп придумал ряд усовершенствований к языку C под собственные нужды. До начала официальной стандартизации язык развивался в основном силами Страуструпа в ответ на запросы программистского сообщества. В 1998 году был ратифицирован международный стандарт языка C++: ISO/IEC 14882:1998 «Standard for the C++ Programming Language»; после принятия технических исправлений к стандарту в 2003 году— нынешняя версия этого стандарта— ISO/IEC 14882:2003.

Ранние версии языка, известные под именем «C с классами», начали появляться с 1980 года. Идея создания нового языка берёт начало от опыта программирования Страуструпа для диссертации. Он обнаружил, что язык моделирования Simula имеет такие возможности, которые были бы очень полезны для разработки большого программного обеспечения, но работает слишком медленно. В то же время язык BCPL достаточно быстр, но слишком близок к языкам низкого уровня и не подходит для разработки большого программного обеспечения. Страуструп начал работать в Bell Labs над задачами теории очередей (в приложении к моделированию телефонных вызовов). Попытки применения существующих в то время языков моделирования оказались неэффективными. Вспоминая опыт своей диссертации, Страуструп решил дополнить язык C (преемник BCPL) возможностями, имеющимися в языке Симула. Язык C, будучи базовым языком системы UNIX, на которой работали компьютеры Bell, является быстрым, многофункциональным и переносимым. Страуструп добавил к нему возможность работы с классами и объектами. В результате, практические задачи моделирования оказались доступными для решения как с точки зрения времени разработки (благодаря использованию Симула-подобных классов) так и с точки зрения времени вычислений (благодаря быстродействию C). В начале в C были добавлены классы (с инкапсуляцией), производные классы, строгая проверка типов, inline-функции и аргументы по умолчанию.

Разрабатывая C с классами (позднее C++), Страуструп также написал программу cfront — транслятор, перерабатывающий исходный код C с классами в исходный код простого C. Новый язык, неожиданно для автора, приобрёл большую популярность среди коллег и вскоре Страуструп уже не мог лично поддерживать его, отвечая на тысячи вопросов.

В 1983 году произошло переименование языка из C с классами в C++. Кроме того, в него были добавлены новые возможности, такие как виртуальные функции, перегрузка функций и операторов, ссылки, константы, пользовательский контроль над управлением свободной памятью, улучшенная проверка типов и новый стиль комментариев (//). Его первый коммерческий выпуск состоялся в октябре 1985 года. В 1985 году вышло также первое издание «Языка программирования C++», обеспечивающее первое описание этого языка, что было чрезвычайно важно из-за отсутствия официального стандарта. В 1989 году состоялся выход C++ версии 2.0. Его новые возможности включали множественное наследование, абстрактные классы, статические функции-члены, функции-константы и защищённые члены.

В 1990 году вышло «Комментированное справочное руководство по C++», положенное впоследствии в основу стандарта. Последние обновления включали шаблоны, исключения, пространства имён, новые способы приведения типов и булевский тип.

Стандартная библиотека C++ также развивалась вместе с ним. Первым добавлением к стандартной библиотеке C++ стали потоки ввода/вывода, обеспечивающие средства для замены традиционных функций C printf и scanf. Позднее самым значительным развитием стандартной библиотеки стало включение в неё Стандартной библиотеки шаблонов.

Никто не обладает правами на язык C++, он является свободным. Однако сам документ стандарта языка (за исключением черновиков) не доступен бесплатно.

Стандартизация языка[]

В 1998 году был опубликован стандарт ISO/IEC 14882:1998 (известный как C++98)[5], разработанный комитетом по стандартизации C++ (ISO/IEC JTC1/SC22/WG21 working group). В течение нескольких лет после опубликования документа, рассмотрев сообщения об ошибках, комитет разработал исправленную версию стандарта, ISO/IEC 14882:2003, вышедшую в 2003 году. В 2005 году был выпущен отчёт «Library Technical Report 1» (кратко называемый TR1). Не являясь официально частью стандарта, отчёт описывает расширения стандартной библиотеки, которые, как ожидалось авторами, должны быть включены в следующую версию языка C++. Степень поддержки TR1 улучшается почти во всех поддерживаемых компиляторах языка C++.

В настоящее время разрабатывается новая версия стандарта, неофициально называемая C++0x.

История названия[]

Название C++ было придумано Риком Масситти (Rick Mascitti) и впервые было использовано в декабре 1983 года. Ранее, на этапе разработки, новый язык назывался «C с классами».[6]

Имя языка, получившееся в итоге, происходит от оператора унарного постфиксного инкремента C ++ (увеличение значения переменной на единицу). Имя C+ не было использовано потому, что является синтаксической ошибкой в C и, кроме того, это имя было занято другим языком. Язык также не был назван D, поскольку «является расширением C и не пытается устранять проблемы путём удаления элементов C».[6]

Философия C++[]

В книге «Дизайн и эволюция C++» Бьёрн Страуструп описывает принципы, которых он придерживался при проектировании C++.[7] Эти принципы объясняют, почему C++ именно такой, какой он есть. Некоторые из них:

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

Обзор языка[]

Стандарт C++ на 2003 год состоит из двух основных частей: описание ядра языка и описание стандартной библиотеки.

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

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

Не объектно-ориентированные возможности[]

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

Комментарии[]

С++ поддерживает как комментарии в стиле C (/* это комментарий */), так и однострочные (// вся оставшаяся часть строки является комментарием).

Типы[]

В C++ доступны следующие встроенные типы:

  • Символьные: char, wchar_t.
  • Целочисленные знаковые: signed char, short int, int, long int.
  • Целочисленные беззнаковые: unsigned char, unsigned short int, unsigned int, unsigned long int.
  • С плавающей точкой: float, double, long double.
  • Логический: bool, имеющий значения true и false.

Операции сравнения возвращают тип bool. Выражения в скобках после if, while приводятся к типу bool.[8]

Функции могут принимать аргументы по ссылке. Например, функция void f(int &x) {x=3;} присваивает своему аргументу значение 3. Функции также могут возвращать результат по ссылке, и ссылки могут быть вне всякой связи с функциями. Например, {double &b=a[3]; b=sin(b);} эквивалентно a[3]=sin(a[3]);. Ссылки в определённой степени сходны с указателями, со следующими особенностями: перед использованием ссылка должна быть инициализирована; ссылка пожизненно указывает на один и тот же адрес; в выражении ссылка обозначает непосредственно тот объект или ту функцию, на которую она указывает, обращение же к объекту или функции через указатель требует разыменование указателя. Существуют и другие отличия в использовании указателей и ссылок.

Разное[]

  • Спецификатор inline позволяет объявлять inline-функции. Функция, определённая внутри тела класса, является inline по умолчанию. Изначально inline-функции задумывались как функции, являющиеся хорошими кандидатами на оптимизацию, при которой в местах обращения к функции компилятор вставит тело этой функции, а не код вызова. В действительности компилятор не обязан реализовывать подстановку тела для inline-функций, но может, исходя из заданных критериев оптимизации, выполнять подстановку тела для функций, которые не объявлены как inline. Пожалуй, наиболее значимой особенностью inline-функции является то, что она может многократно определяться в нескольких единицах трансляции (при этом inline-функция должна быть определена во всех единицах трансляции, где она используется), в то время как функция, не являющаяся inline, может определяться в программе не более одного раза. Пример:

inline double Sqr(double x) {return x*x;}.

  • Описатель volatile используется в описании переменных и информирует компилятор, что значение данной переменной может быть изменено способом, который компилятор не в состоянии отследить. Для переменных, объявленных volatile, компилятор не должен применять средства оптимизации, изменяющие положение переменной в памяти (например, помещающие её в регистр) или полагающиеся на неизменность значения переменной в промежутке между двумя присваиваниями ей значения.
  • Если описана структура, класс, объединение (union) или перечисление (enum), её имя является именем типа, например:
struct Time {
    int hh, mm, ss;
};
Time t1, t2;
  • Добавлены пространства имён (namespace). Например, если написать
namespace Foo {
   const int x=5;
   typedef int** T;
   void f(y) {return y*x};
   double g(T);
   ...
}

то вне фигурных скобок следует обращаться к T, x, f, g как Foo::T, Foo::x, Foo::f и Foo::g соответственно. Если в каком-то файле нужно обратиться к ним непосредственно, можно написать

using namespace Foo;

Или же

using Foo::T;

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

namespace {
    ...
}

Все имена, описанные в нём, доступны в текущей единице трансляции и больше нигде.

  • Один или несколько последних аргументов функции могут задаваться по умолчанию. К примеру, если функция описана как void f(int x, int y=5, int z=10), вызовы f(1), f(1,5) и f(1,5,10) эквивалентны.
  • При описании функций отсутствие аргументов в скобках означает, в отличие от C, что аргументов нет, а не то, что они неизвестны. Если аргументы неизвестны, надо пользоваться многоточием, например, int printf(const char* fmt, …).
  • Внутри структуры или класса можно описывать вложенные типы, как через typedef, так и через описание других классов, а также перечислений. Для доступа к таким типам вне класса, к имени типа добавляется имя структуры или класса и два двоеточия:
struct S {
    typedef int** T;
    T x;
};
S::T y;
  • Могут быть несколько функций с одним и тем же именем, но разными типами или количеством аргументов (перегрузка функций; при этом тип возвращаемого значения на перегрузку не влияет). Например, вполне можно писать:
void Print(int x);
void Print(double x);
void Print(int x, int y);
  • Смысл некоторых операторов применительно к пользовательским типам можно определять через объявление соответствующих операторных функций. К примеру, так:
struct Date {int day, month, year;};
void operator ++(struct Date& date);

Операторные функции во многом схожи с обычными (неоператорными) функциями. За исключением операторов new, new[], delete и delete[], нельзя переопределять поведение операторов для встроенных типов (скажем, переопределять умножение значений типа int); нельзя выдумывать новые операторы, которых нет в C++ (скажем, **); нельзя менять количество операндов, предусмотренное для оператора, а также нельзя менять существующие приоритеты и ассоциативность операторов (скажем, в выражении a+b*c сначала будет выполняться умножение, а потом сложение, к каким бы типам ни принадлежали a, b и c). Можно переопределить операции [] (с одним параметром) и () (с любым числом параметров).

  • Добавлены шаблоны (template). Например, template<class T> T Min(T x, T y) {return x<y?x:y;} определяет функцию Min для любых типов. Шаблоны могут задавать не только функции, но и типы. Например, template<class T> struct Array{int len; T* val;}; определяет массив значений любого типа, после чего мы можем писать Array<float> x;
  • В дополнение к функциям malloc и free введены операторные функции operator new, operator new[], operator delete и operator delete[], а также операторы new, new[], delete и delete[]. Если T — произвольный объектный тип, не являющийся типом массива, X - произвольный объектный тип и A - тип массива из некоторого количества n элементов, имеющих тип X, то
    • new T выделяет память (посредством вызова функции operator new), достаточную для размещения одного объекта типа Т, возможно, инициализирует объект в этой памяти, и возвращает указатель типа Т* (например, Т* p = new T).
    • new X[n] и new A выделяют память (посредством вызова функции operator new[]), достаточную для размещения n объектов типа X, возможно, инициализируют каждый объект в этой памяти, и возвращают указатель типа X* (например, X* p = new X[n]).
    • delete p — разрушает объект (не являющийся массивом), на который ссылается указатель p, и освобождает область памяти (посредством вызова функции operator delete), ранее выделенную для него new-выражением.
    • delete [] p — разрушает каждый объект в массиве, на который ссылается указатель p, и освобождает область памяти (посредством вызова функции operator delete[]), ранее выделенную для этого массива new-выражением.

Операция delete проверяет, что её аргумент не NULL, в противном случае она ничего не делает. При создании и удалении экземпляров классов с нетривиальными конструкторами и деструкторами с помощью new и delete компилятор генерирует вызовы конструктора и деструктора класса (см. ниже).

Объектно-ориентированные особенности языка[]

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

В стандарте C++ под классом (class) подразумевается пользовательский тип, объявленный с использованием одного из ключевых слов class, struct или union, под структурой (structure) подразумевается класс, определённый через ключевое слово struct, и под объединением (union) подразумевается класс, определённый через ключевое слово union.

Описание функций в теле класса[]

В теле класса можно указать только заголовок функции, а можно описать всю функцию (см. пример с функцией Alloc ниже. В этом случае она считается встраиваемой (inline)

Константные функции-члены[]

Нестатические функции-члены (и только они) могут иметь описатель const

class Array {
...
    inline double operator[] (int n) const;

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

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

В C++ при наследовании одного класса от другого наследуется реализация класса, плюс класс-наследник может добавлять свои поля и функции или переопределять функции базового класса. Множественное наследование разрешено.

Конструктор наследника вызывает конструкторы базовых классов, а затем конструкторы нестатических членов-данных, являющихся экземплярами классов. Деструктор работает в обратном порядке.

Наследование бывает публичным, защищённым и собственным:

Доступ члена базового класса/режим наследования private-член protected-член public-член
private-наследование недоступен private private
protected-наследование недоступен protected protected
public-наследование недоступен protected public

Наследник— это больше чем базовый класс, поэтому, если наследование открытое, то он может использоваться везде, где используется базовый класс, но не наоборот.

Полиморфизм[]

Полиморфизмом в программировании называется переопределение наследником функций-членов базового класса, например:

class Figure {
    ...
    void Draw() const;
    ...
};

class Square : public Figure {
    ...
    void Draw() const;
    ...
};

class Circle : public Figure {
    ...
    void Draw() const;
    ...
};

Какая именно из функций будет вызвана— Figure::Draw(), Square::Draw() или Circle::Draw() — определяется во время компиляции. Например:

Circle *c = new Circle(0,0,5);
Figure *f = c; // Всё ok: Figure — базовый класс для Circle
c->Draw();
f->Draw(); // Указатели друг другу равны, но для f будет вызвана другая функция, чем для c

Несмотря на то, что оба указателя указывают на один и тот же объект класса Circle, для c будет вызвана Circle::Draw(), а для fFigure::Draw(), поскольку f — указатель на объект класса Figure. Такой полиморфизм называется статическим.

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

class Figure {
    ...
    virtual void Draw() const;
    ...
};

class Square : public Figure {
    ...
    void Draw() const;
    ...
};

class Circle : public Figure {
    ...
    void Draw() const;
    ...
};

Figure *figures[10];
figures[0] = new Square(1, 2, 10);
figures[1] = new Circle(3, 5, 8);
...
for (int i = 0; i < 10; i++)
    figures[i]->Draw();

В этом случае для каждого элемента массива будет вызвана Square::Draw() или Circle::Draw() в зависимости от вида фигуры.

Чисто виртуальной функцией называется виртуальная функция-член, которая объявлена со спецификатором = 0:

class Figure {
    ...
    virtual void Draw() const = 0;
);

Чисто виртуальная функция может быть оставлена без определения, кроме случая, когда требуется произвести её вызов.

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

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

Основным способом организации информации в C++ являются классы. В отличие от структуры (struct) языка C, которая может состоять только из полей и вложенных типов, класс (class) C++ может состоять из полей, вложенных типов и функций-членов (member functions). Инкапсуляция в С++ реализуется через указание уровня доступа к членам класса: они бывают публичными (открытыми, public), защищёнными (protected) и собственными (закрытыми, приватными, private). В C++ структуры формально отличаются от классов лишь тем, что по умолчанию члены и базовые классы у структуры публичные, а у класса— собственные.

Доступ private protected public
Сам класс да да да
Друзья да да да
Наследники нет да да
Извне нет нет да

Проверка доступа происходит во время компиляции, попытка обращения к недоступному члену класса вызовет ошибку компиляции.

Пример класса, реализующего одномерный массив (это просто иллюстрация, а не образец дизайна!):

class Array {
public:
    Array() : len(0), val(NULL) {}
    Array(int _len) : len(_len) {val = new double[_len];}
    Array(const Array& a);
    ~Array() { Free(); }

    inline double Elem(int i);
    inline void ChangeElem(int i, double x);
protected:
    void Alloc(int _len)  {if (len==0) Free(); len=_len; val=new double[len];}
    void Free();
    int len;
    double* val;
};

Здесь класс Array имеет 2 публичных функции-члена, 2 защищённых поля, 3 публичных конструктора и публичный деструктор. Описатель inline означает подсказку компилятору, что вместо вызова функции её код следует встроить в точку вызова, чем часто можно достичь большей эффективности.

Друзья[]

Функции-друзья — это функции, не являющиеся функциями-членами и тем не менее имеющие доступ к защищённым и собственным полям и функциям-членам класса. Они должны быть описаны в теле класса как friend. Например:

class Matrix {
    ...
    friend Matrix Multiply(Matrix m1, Matrix m2);
    ...
};

Matrix Multiply(Matrix m1, Matrix m2) {
    ...
}

Здесь функция Multiply может обращаться к любым полям и функциям-членам класса Matrix.

Существуют также классы-друзья. Если класс A — друг класса B, то все его функции-члены могут обращаться к любым полям и функциям членам класса B. Например:

class Matrix {
    ...
    friend class Vector;
    ...
};

Однако в C++ не действует правило «друг моего друга— мой друг».

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

Конструкторы и деструктор[]

В классах всегда есть специальные функции— конструкторы и деструкторы — либо явно объявленные, либо сгенерированные компилятором автоматически.

Конструктор вызывается при создании и инициализации объекта данного типа; деструктор— при уничтожении.

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

Конструкторы обозначаются как одноименные классу функции (Array::Array), деструкторы— имя класса с тильдой (Array::~Array).

Конструктор без параметров или конструктор, все параметры которого имеют аргументы по умолчанию, называется конструктором по умолчанию, нешаблонный конструктор с первым параметром-ссылкой на тот же класс (например, Array::Array(const Array&)) и остальными параметрами (если таковые есть), имеющими аргументы по умолчанию, — конструктором копирования, он вызывается при создании нового объекта, являющегося копией уже существующего объекта:

Array a(5); // вызывается Array::Array(int)
Array b; // вызывается Array::Array()
Array c(a); // вызывается Array::Array(const Array&)
Array d=a; // то же самое
b=c; // происходит вызов оператора =
            // если он не определён (как в данном случае), то вызывается сгенерированный компилятором оператор присваивания, который
            // осуществляет копирование базовых подобъектов и почленное копирование нестатических членов-данных.
            // как правило конструктор копий и оператор присваивания переопределяются попарно

Оператор new тоже вызывает конструкторы, а delete — деструкторы.

По умолчанию, каждый класс имеет неявно объявленные конструктор без параметров, копирующий конструктор, копирующий оператор присваивания и деструктор.

Класс может иметь сколько угодно конструкторов (с разными наборами параметров), но только один деструктор (без параметров).

Перегрузка операторов[]

Функции-члены могут быть операторами:

class Array {
...
    inline double &operator[] (int n) { return val[n]; }

И далее

Array a(10);
...
double b = a[5];

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

Стандартная библиотека С++ включает в себя как сущности, специфичные для С++, так и, частично, стандартную библиотеку C с небольшими изменениямиШаблон:Нет АИ, которые делают её более подходящей для языка C++Шаблон:Нет АИ. Стандарт C++ содержит нормативную ссылку на стандарт C от 1990 года и не определяет самостоятельно те функции стандартной библиотеки, которые заимствуются из стандартной библиотеки C. Возможности библиотек активизируются использованием директивы #include для включения стандартных файлов. Всего в стандарте C++ определено 50 таких файлов. Библиотека состоит из следующих разделов:

Поддержка языка[]

  • <cstddef> — описания стандартных типов
  • <limits>, <climits>, <cfloat> — средства доступа к свойствам реализации языка
  • <cstdlib> — средства завершения программы
  • <new> — управление динамическим выделением памяти
  • <typeinfo> — получение информации о типах во время выполнения программы
  • <exception> — обработка исключеий
  • <cstdarg>, <csetjmp>, <ctime>, <csignal>, <cstdlib> — прочие средства времени выполнения

Средства диагностики[]

  • <stdexcept> — стандартные классы исключений
  • <cassert> — диагностические утверждения
  • <cerrno> — средства работы с кодами ошибок

Средства общего назначения[]

  • <utility> — обобщённые операторы и пары
  • <functional> — стандартные обобщённые функторы, операции связывания аргументов и функциональные адаптеры
  • <memory> — средства управления памятью, в том числе аллокатор, специальные алгоритмы и класс auto_ptr
  • <ctime> — типы и функции для работы с датами и временем

Средства работы с текстовыми строками[]

  • <string> — характеристики символов
  • <string> — строковые классы
  • <cctype>, <cwctype>, <cstring>, <cwchar>, <cstdlib> — средства работы с символьными строками, завершающимися нулём

Средства интернационализации[]

  • <locale> — объекты национально-культурного контекста
  • <clocale> — объекты национально-культурного контекста стандартной библиотеки C

Контейнеры[]

  • <deque>, <list>, <queue>, <stack>, <vector> — последовательные контейнеры и контейнерные адаптеры
  • <map>, <set>, <bitset> — ассоциативные контейнеры

Итераторы[]

  • <iterator> — характеристики и стандартные теги итераторов, обратные итераторные адаптеры и итераторы вставки, итераторы потоков ввода-вывода

Алгоритмы[]

  • <algorithm> — немодифицирующие алгоритмы, модифицирующие алгоритмы, алгоритмы сортировки и упорядоченных интервалов
  • <cstdlib> — алгоритмы стандартной библиотеки языка C

Численные алгоритмы[]

  • <complex> — класс комплексных чисел
  • <valarray> — численные массивы
  • <numeric> — обобщённые численные алгоритмы
  • <cmath>, <cstdlib> — математические функции стандартной библиотеки языка C

Средства ввода-вывода[]

  • <iosfwd> — предварительные объявления типов
  • <iostream> — классы стандартных потоков ввода-вывода
  • <ios> — базовые классы библиотеки
  • <streambuf> — классы потоковых буферов
  • <istream>, <ostream>, <iomanip> — средства форматирования, потоковые манипуляторы
  • <sstream>, <cstdlib> — строковые потоки
  • <fstream>, <cstdio>, <cwchar> — файловые потоки

Реализации[]

STL до включения в стандарт C++ была сторонней разработкой, в начале— фирмы HP, а затем SGI. Стандарт языка не называет её «STL», так как эта библиотека стала неотъемлемой частью языка, однако многие люди до сих пор используют это название, чтобы отличать её от остальной части стандартной библиотеки (потоки ввода/вывода (iostream), подраздел C и другие).

Проект под названием STLport[9], основанный на SGI STL, осуществляет постоянное обновление STL, IOstream и строковых классов. Некоторые другие проекты также занимаются разработкой частных применений стандартной библиотеки для различных конструкторских задачШаблон:Нет АИ. Каждый производитель компиляторов C++ обязательно поставляет какую-либо реализацию этой библиотеки, так как она является очень важной частью стандарта и широко используется.

Отличия С++ от C[]

Новые возможности по сравнению с C[]

Шаблон:Викиучебник Нововведениями C++ в сравнении с C являются:

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

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

В C++ появились комментарии в виде двойной косой черты (//), которые были в предшественнике C — языке BCPL.

Некоторые особенности C++ позднее были перенесены в C, например, ключевые слова const и inline, объявления в циклах for и комментарии в стиле C++ (//). В более поздних реализациях C также были представлены возможности, которых нет в C++, например макросы vararg и улучшенная работа с массивами-параметрами.

C++ не включает в себя C[]

Несмотря на то, что большая часть кода C будет справедлива и для C++, C++ не является надмножеством C и не включает его в себя. Существует и такой верный для C код, который неверен для C++. Это отличает его от Объектного 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;
}

Дальнейшее развитие[]

Текущий стандарт языка ISO/IEC 14882:2003(E) был принят в 2003 году. Неофициально его обозначают как C++03. Следующая версия стандарта имеет неофициальное обозначение C++0x.

C++ продолжает развиваться, чтобы отвечать современным требованиям. Одна из групп, занимающихся языком C++ в его современном виде и направляющих комитету по стандартизации C++ советы по его улучшению— это Boost. Например, одно из направлений деятельности этой группы— совершенствование возможностей языка путём добавления в него особенностей метапрограммирования.

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

Тем не менее (по состоянию на время написания этой статьиШаблон:Когда) среди компиляторов C++ всё ещё продолжается битваШаблон:Нет АИ за полную реализацию стандарта C++, особенно в области шаблонов — части языка, совсем недавно полностью разработанной комитетом стандартизации.

Ключевое слово export[]

Одной из точек преткновения в этом вопросе является ключевое слово export, используемое также и для разделения объявления и определения шаблонов.

Первым компилятором, поддерживающим export в шаблонах, стал Comeau C++ в начале 2003 года (спустя 5 лет после выхода стандарта C++98). В 2004 году бета-версия компилятора Borland C++ Builder X также начала его поддержку.

Оба этих компилятора основаны на фронт-энде EDG. Другие компиляторы, такие как Microsoft Visual C++ или GCC (GCC 3.4.4), вообще этого не поддерживают. Герб Саттер, секретарь комитета по стандартизации C++, рекомендовал убрать export из будущих версий стандарта по причине серьёзных сложностей в полноценной реализации, однако впоследствии его решили оставить.

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

Примеры программ на C++[]

Пример №1[]

Это пример программы, которая не делает ничего. Она начинает выполняться и немедленно завершается. Она состоит из основного потока: функции main(), которая обозначает точку начала выполнения программы на C++.

int main()
{
    return 0;
}

Стандарт C++ требует, чтобы функция main() возвращала тип int. Программа, которая имеет другой тип возвращаемого значения функции main(), не соответствует стандарту C++.

Стандарт не говорит о том, что на самом деле означает возвращаемое значение функции main(). Традиционно оно интерпретируется как код возврата программы. Стандарт гарантирует, что возвращение 0 из функции main() показывает, что программа была завершена успешно.

Завершение программы на C++ с ошибкой традиционно обозначается путём возврата ненулевого значения.

Пример №2[]

Эта программа также ничего не делает, но более лаконична.

int main(){}

В C++, если выполнение программы доходит до конца функции main(), то это эквивалентно return 0;. Это неверно для любой другой функции кроме main().

Пример №3[]

Это пример программы Hello World, которая выводит это знаменитое сообщение, используя стандартную библиотеку, и завершается.

#include <iostream> // это необходимо для std::cout и std::endl
int main()
{
    std::cout << "Hello, world!" << std::endl;
}

Пример №4[]

Современный C++ позволяет решать простым способом и более сложные задачи. Этот пример демонстрирует кроме всего прочего использование контейнеров стандартной библиотеки шаблонов (STL).

#include <iostream> // для использования std::cout
#include <vector> // для std::vector<>
#include <map> // для std::map<> и std::pair<>
#include <algorithm> // для std::for_each()
#include <string> // для std::string

using namespace std; // используем пространство имён "std"

void display_item_count(pair< string const, vector<string> > const& person) {
   // person - это пара двух объектов: person.first - это его имя,
   // person.second - это список его предметов (вектор строк)
   cout << person.first << " is carrying " << person.second.size() << " items" << endl;
}

int main()
{
   // объявляем карту со строковыми ключами и данными в виде векторов строк
   map< string, vector<string> > items;

   // Добавим в эту карту пару человек и дадим им несколько предметов
   items["Anya"].push_back("scarf");
   items["Dimitri"].push_back("tickets");
   items["Anya"].push_back("puppy");

   // Переберём все объекты в контейнере
   for_each(items.begin(), items.end(), display_item_count);
}

В этом примере для простоты используется директива использования пространства имён, в настоящей же программе обычно рекомендуется использовать объявления, которые аккуратнее директив:

#include <vector>

int main()
{
    using std::vector;

    vector<int> my_vector;
}

Здесь директива помещена в область функции, что уменьшает шансы столкновений имён (это и стало причиной введения в язык пространств имён). Использование объявлений, сливающих разные пространства имён в одно, разрушает саму концепцию пространства имён.Шаблон:Нет АИ

Пример №5[]

Популярные библиотеки boost в сочетании со стандартными средствами языка позволяют очень лаконично и наглядно записывать код. В приведённом ниже примере вычисляется скалярное произведение векторов нечётных чисел и квадратов. В коде вектора значений представлены ленивыми STL-подобными последовательностями.

#include <iostream>
#include <numeric>
#include <boost/iterator/counting_iterator.hpp>
#include <boost/iterator/transform_iterator.hpp>

int odd(int i)
{
  return 2 * i + 1;
}

int square(int i)
{
  return i * i;
}

typedef boost::counting_iterator <int> counter;
typedef boost::transform_iterator <int (*)(int), counter> transformer;

transformer odds(int n)
{
  return transformer(counter(n), odd);
}

transformer squares(int n)
{
  return transformer(counter(n), square);
}

int main()
{
  using namespace std;

  cout << "Enter vector length: ";
  int n; cin >> n;

  cout << inner_product( odds(0), odds(n), squares(0), 0 ) << endl;
}

Данный пример демонстрирует так называемый «плоский» стиль записи. Это название связано с тем, что алгоритмы STL позволяют записывать код без циклов, соответственно ширина отступов в отформатированном коде примерно постоянна. Сторонники такого подхода считают, что программисту, знакомому со стандартной библиотекой С++, достаточно строчки с вызовом inner_product(), чтобы понять, что делает программа. С этой точки зрения вызов inner_product близок к словесному описанию задачи: «вычислить скалярное произведение векторов нечётных чисел и квадратов для значений от нуля до n».


Достоинства языка и его критика[]

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

Достоинства[]

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

  • Поддерживаются различные стили и технологии программирования, включая традиционное директивное программирование, ООП, обобщённое программирование, метапрограммирование (шаблоны, макросы).
  • Предсказуемое выполнение программ является важным достоинством для построения систем реального времени. Весь код, неявно генерируемый компилятором для реализации языковых возможностей (например, при преобразовании переменной к другому типу), определён в стандарте. Также строго определены места программы, в которых этот код выполняется. Это даёт возможность замерять или рассчитывать время реакции программы на внешнее событие.
  • Автоматический вызов деструкторов объектов при их уничтожении, причём в порядке, обратном вызову конструкторов. Это упрощает (достаточно объявить переменную) и делает более надёжным освобождение ресурсов (память, файлы, семафоры ит. п.), а также позволяет гарантированно выполнять переходы состояний программы, не обязательно связанные с освобождением ресурсов (например, запись в журнал).
  • Пользовательские функции-операторы позволяют кратко и ёмко записывать выражения над пользовательскими типами в естественной алгебраической форме.
  • Язык поддерживает понятия физической (const) и логической (mutable) константности. Это делает программу надёжнее, так как позволяет компилятору, например, диагностировать ошибочные попытки изменения значения переменной. Объявление константности даёт программисту, читающему текст программы дополнительное представление о правильном использовании классов и функций, а также может являться подсказкой для оптимизации. Перегрузка функций-членов по признаку константности позволяет определять изнутри объекта цели вызова метода (константный для чтения, неконстантный для изменения). Объявление mutable позволяет сохранять логическую константность при использовании кэшей и ленивых вычислений.
  • Используя шаблоны, возможно создавать обобщённые контейнеры и алгоритмы для разных типов данных, а также специализировать и вычислять на этапе компиляции.
  • Возможность имитации расширения языка для поддержки парадигм, которые не поддерживаются компиляторами напрямую. Например, библиотека Boost.Bind позволяет связывать аргументы функций.
  • Возможность создания встроенных предметно-ориентированных языков программирования. Такой подход использует, например библиотека Boost.Spirit, позволяющая задавать EBNF-грамматику парсеров прямо в коде C++.
  • Используя шаблоны и множественное наследование можно имитировать классы-примеси и комбинаторную параметризацию библиотек. Такой подход применён в библиотеке Loki, класс SmartPtr которой позволяет, управляя всего несколькими параметрами времени компиляции, сгенерировать около 300 видов «умных указателей» для управления ресурсами.
  • Кроссплатформенность: стандарт языка накладывает минимальные требования на ЭВМ для запуска скомпилированных программ. Для определения реальных свойств системы выполнения в стандартной библиотеке присутствуют соответствующие возможности (например, std::numeric_limits <T>). Доступны компиляторы для большого количества платформ, на языке C++ разрабатывают программы для самых различных платформ и систем.
  • Эффективность. Язык спроектирован так, чтобы дать программисту максимальный контроль над всеми аспектами структуры и порядка исполнения программы. Ни одна из языковых возможностей, приводящая к дополнительным накладным расходам, не является обязательной для использования— при необходимости язык позволяет обеспечить максимальную эффективность программы.
  • Имеется возможность работы на низком уровне с памятью, адресами.
  • Высокая совместимость с языком C, позволяющая использовать весь существующий C-код (код на C может быть с минимальными переделками скомпилирован компилятором C++; библиотеки, написанные на C, обычно могут быть вызваны из C++ непосредственно без каких-либо дополнительных затрат, в том числе и на уровне функций обратного вызова, позволяя библиотекам, написанным на C, вызывать код, написанный на С++).

Критика[]

Критику языка можно разделить на несколько групп заявлений. Критики полагают, что:

  • Синтаксис, унаследованный от C, неудобен
  • С++ содержит слишком много возможностей, и что они могут быть опасны
  • С++, наоборот, не содержит некоторых возможностей
  • Языку С++ присущи проблемы производительности

Критика синтаксиса[]

  • Операция присваивания обозначается как =, а операция сравнения как ==. Их легко спутать, при этом операция присваивания возвращает значение, поэтому присваивание на месте выражения является синтаксически корректным, а в конструкциях цикла и ветвления появление числа на месте логического значения также допустимо, так что ошибочная конструкция оказывается синтаксически правильной. Типичный пример подобной ошибки:
    if (x=0) { операторы }
    
    Здесь в условном операторе по ошибке написано присваивание вместо сравнения. В результате, вместо того, чтобы сравнить текущее значение x с нулём, программа присвоит x нулевое значение, а потом интерпретирует его как значение условия в операторе if. Так как нуль соответствует логическому значению «ложь», блок операторов в условной конструкции не выполнится никогда. Ошибки такого рода трудно выявлять, но во многих современных компиляторах предлагается диагностика некоторых подобных конструкций.
  • Операции присваивания (=), инкрементации (++), декрементации (--) и другие возвращают значение. В сочетании с обилием операций это позволяет, хотя и не обязывает, создавать трудночитаемые выражения. Наличие этих операций в C было вызвано желанием получить инструмент ручной оптимизации кодаШаблон:Нет АИ, но в настоящее время оптимизирующие компиляторы обычно генерируют оптимальный код и на традиционных выражениях. С другой стороны, один из основных принципов языков C и C++ — позволять программисту писать в любом стиле, а не навязывать «хороший» стиль.
  • Некоторые преобразования типов неинтуитивныШаблон:Нет АИ. В частности, операция над беззнаковым и знаковым числами выдаёт беззнаковый результат.
  • Многие конструкции С++ позволяют делать то же самое, что и конструкции C, также присутствующие в С++. Это иногда сбивает с толку новичков. Например, приведение типов при помощи dynamic_cast позволяет привести указатель или ссылку строго в пределах иерархии классов. Это делает код более надёжным, декларативным и позволяет находить приведения в пределах иерархии при помощи инструментов типа grep. Однако вследствие требования высокой степени совместимости с C старое приведение типов всё ещё поддерживается.

Критика наличия возможностей[]

  • C++ позволяет пропускать break в ветви оператора switch с целью последовательного выполнения нескольких ветвей. Такой же подход принят в языке Java [10]. Есть мнение, что это затрудняет понимание кода. Например, в языке C# необходимо всегда писать либо break, либо использовать goto case N для явного указания порядка выполнения [11].
  • Макросы (#define) являются мощным, но опасным средством. Они сохранены в C++ несмотря на то, что необходимость в них, благодаря шаблонам и встроенным функциям, не так уж великаШаблон:Нет АИ. В унаследованных стандартных C-библиотеках много потенциально опасных макросовШаблон:Нет АИ.

Критика отсутствия возможностей[]

  • Препроцессор, унаследованный от C, очень примитивен. Это приводит с одной стороны к тому, что с его помощью нельзя (или тяжело) осуществлять некоторые задачи метапрограммирования, а с другой, вследствие своей примитивности, он часто приводит к ошибкам и требует много действий по обходу потенциальных проблем. Некоторые языки программирования (например, Scheme и Nemerle) имеют намного более мощные и более безопасные системы метапрограммирования (также называемые макросами, но мало напоминающие макросы C/C++).
  • Плохая поддержка модульности (по сути, в классическом C модульность на уровне языка отсутствует, её обеспечение переложено на компоновщик). Подключение интерфейса внешнего модуля через препроцессорную вставку заголовочного файла (#include) серьёзно замедляет компиляцию при подключении большого количества модулей (потому что результирующий файл, который обрабатывается компилятором, оказывается очень велик). Эта схема без изменений скопирована в C++. Для устранения этого недостатка многие компиляторы реализуют механизм Шаблон:Translation2.
  • Метапрограммирование на основе шаблонов C++ сложно и при этом ограничено в возможностях. Оно состоит в реализации средствами шаблонов C++ интерпретатора примитивного функционального языка программирования, выполняющегося во время компиляции. Сама по себе данная возможность весьма привлекательна, но такой код весьма трудно воспринимать и отлаживать. Менее распространённые[12] языки Lisp/Scheme, Nemerle имеют более мощные и одновременно более простые для восприятия подсистемы метапрограммирования. Кроме того, в языке D реализована сравнимая по мощности, но значительно более простая в применении подсистема шаблонного метапрограммирования.
  • Явная поддержка функционального программирования присутствует только в будущем стандарте C++0x. Данный пробел устраняется различными библиотеками (Loki, Boost), использующими средства метапрограммирования для расширения языка функциональными конструкциями (например, поддержкой лямбд/анонимных методов), но качество подобных решений значительно уступает качеству встроенных в функциональные языки решений. Такие возможности функциональных языков, как сопоставление с образцом, вообще крайне сложно эмулировать средствами метапрограммирования.
  • Некоторые считают недостатком языка C++ отсутствие встроенной системы сборки мусора. С другой стороны, средства C++ позволяют реализовать сборку мусора на уровне библиотеки [13]. Противники сборки мусора полагают, что RAII является более достойной альтернативой. С++ позволяет пользователю самому выбирать стратегию управления ресурсами.

Критика производительности[]

  • Иногда шаблоны приводят к порождению кода очень большого объёма[14]. Для снижения размера машинного кода можно специальным образом подготавливать исходный код[15]. Другим решением является стандартизованная ещё в 1998 году возможность экспорта шаблонов. Некоторые авторы считают, что её трудно реализовать и поэтому она доступна не во всех компиляторах[16][17][18]. «Раздувание» машинного кода вследствие использования шаблонов часто преувеличивается, и современные компиляторы во многих случаях успешно устраняют это явление[19].

Контраргументы[]

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

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

Сравнение C++ с языком Java[]

Целью создания C++ было расширение возможностей C, наиболее распространённого языка системного программирования. Ориентированный на ту же самую область применения, C++ унаследовал множество не самых лучших, с теоретической точки зрения, особенностей CШаблон:Неопределённость. Перечисленные выше принципы, которых придерживался автор языка, предопределили многие недостатки C++Шаблон:Нет АИ.

В области прикладного программирования альтернативой C++ стал его язык-потомок, Java. Несмотря на преемственность по отношению к C++, Java строилась на принципиально иной основе, её разработчики не были связаны требованиями совместимости с языком-предком и обеспечения максимально достижимой эффективности, благодаря чему они смогли кардинально переработать язык, отказаться от множества синтаксических средств, чтобы добиться идеологической целостности языка. Позже фирма Майкрософт предложила язык C#, представляющий собой ещё одну переработку C++ в том же направлении, что и Java. В дальнейшем появился язык Nemerle, в котором к средствам C# добавлены средства функционального программирования. Ещё позже появилась попытка объединения эффективности C++ с безопасностью и скоростью разработки Java и C# — был предложен язык D, который пока не получил широкого признания.

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

Синтаксис
C++ сохраняет совместимость с C, насколько это возможно. Java сохраняет внешнее подобие C и C++, но в действительности сильно отличается от них— из языка удалено большое число синтаксических средств, объявленных необязательными. В результате программы на Java бывают более громоздки по сравнению с их аналогами на С++. С другой стороны, Java проще, что облегчает как изучение языка, так и создание трансляторов для него.
Исполнение программы
Java-код компилируются в промежуточный код, который в дальнейшем интерпретируется или компилируется, тогда как C++ изначально ориентирован на компиляцию в машинный код заданной платформы (хотя, теоретически, ничто не мешает создавать для C++ трансляторы в промежуточный код). Это уже определяет разницу в сферах применения языков: Java вряд ли может быть использована при написании таких специфических программ, как драйверы устройств или низкоуровневые системные утилиты. Механизм исполнения Java делает программы, даже откомпилированные (в байт-код) полностью переносимыми. Стандартное окружение и среда исполнения позволяют выполнять программы на Java на любой аппаратной платформе и в любой ОС, без каких-либо изменений, усилия по портированию программ минимальны (при соблюдении рекомендаций по созданию переносимых программ— и вовсе нулевые). Ценой переносимости становится потеря эффективности— работа среды исполнения приводит к дополнительным накладным расходам.
Управление ресурсами
C++ позволяет использовать принцип «захват ресурсов путём инициализации» (RAII), при котором ресурсы ассоциированы с объектом и автоматически освобождаются при разрушении объекта (например, std::vector и std::ifstream). Также возможен подход, когда программист, выделяя ресурсы (память под объекты, открытые файлы ит. п.), обязан явно позаботиться о своевременном их освобождении. Java работает в среде со сборкой мусора, которая автоматически отслеживает прекращение использования объектов и освобождает занимаемую ими память, если в этом есть необходимость, в некоторый неопределённый момент времени. Ручное управление предпочтительнее в системном программировании, где требуется полный контроль над ресурсами, RAII и сборка мусора удобнее в прикладном программировании, поскольку в значительной степени освобождают программиста от необходимости отслеживать момент прекращения использования ресурсов. Сборщик мусора Java требует системных ресурсов, что снижает эффективность выполнения программ, лишает программы на Java детерминированности выполнения и способен следить только за памятью. Файлы, каналы, сокеты, объекты графического интерфейса программист на Java всегда освобождает явно.
Стандартизация окружения
В Java есть чётко определённые стандарты на ввод-вывод, графику, геометрию, диалог, доступ к базам данных и прочим типовым приложениям. C++ в этом отношении гораздо более свободен. Стандарты на графику, доступ к базам данных ит. д. являются недостатком, если программист хочет определить свой собственный стандарт.
Указатели
C++ сохраняет возможность работы с низкоуровневыми указателями. В Java указателей нет. Использование указателей часто является причиной труднообнаруживаемых ошибок, но необходимо для низкоуровневого программирования. В принципе, C++ обладает набором средств (конструкторы и деструкторы, стандартные шаблоны, ссылки), позволяющих почти полностью исключить выделение и освобождение памяти вручную и опасные операции с указателями. Однако такое исключение требует определённой культуры программирования, в то время как в языке Java оно реализуется автоматически.
Парадигма программирования
В отличие от С++, Java является чисто объектно-ориентированным языком, без возможности процедурного программирования. Для объявления свободных функций или глобальных переменных в Java необходимо создавать фиктивные классы, содержащие только static члены[20]. Для задания главной функции даже самой простой программы на Java необходимо поместить её в класс[21].
Динамическая информация о типах
в C++ RTTI ограничена возможностью сравнивать типы объектов между собой и с буквальными значениями типов. В системе Java доступна более подробная информация о типах. Эту возможность можно было бы реализовать в C++, имея полную информацию о типах во время компиляции CTTI.
Препроцессор
C++ использует препроцессор для включения определений функций и классов, для подключения библиотек, полностью выполненных в исходном коде, а также позволяет осуществлять метапрограммирование с использованием препроцессора, которое, в частности, решает сложные проблемы высокоуровневого дублирования кода[22]. Есть мнение, что этот механизм небезопасен, так как имена макросов препроцессора глобальны, а сами макросы почти никак не связаны с конструкциями языка. Это может приводить к сложным конфликтам имён. С другой точки зрения, C++ предоставляет достаточно средств (константы, шаблоны, встроенные функции) для того, чтобы практически полностью исключить использование препроцессора. Java исключила препроцессор полностью, избавившись разом от всех проблем с его использованием, потеряв при этом возможности метапрограммирования препроцессора и текстовых замен в коде средствами языка.

Отличия языков приводят к ожесточённым спорам между сторонниками двух языков о том, какой язык лучше. Споры эти во многом беспредметны, поскольку сторонники Java считают различия говорящими в пользу Java, а сторонники C++ полагают обратное. Некоторая аргументация устаревает со временем, например, упрёки в неэффективности Java из-за наличия среды исполнения, бывшие справедливыми в первой половине 1990-х годов, в результате лавинообразного роста производительности компьютеров и появления более эффективной техники исполнения (JIT) в значительной мере потеряли актуальностьШаблон:Нет АИ. C++, в свою очередь, развивался, и ряд его недостатков устранён в последних версиях стандарта (например, появился механизм частичной спецификации шаблонов).

Далеко не все программисты являются сторонниками одного из языковШаблон:Нет АИ. По мнению большинстваШаблон:Нет АИ программистов, Java и C++ не являются конкурентами, потому что обладают различными областями применимости. Другие считаютШаблон:Нет АИ, что выбор языка для многих задач является вопросом личного вкуса.

См. также[]

  • Тернарная условная операция#C++

Примечания[]

Литература[]

  1. 1,0 1,1 Шаблон:Книга
  2. Шаблон:Cite book
  3. Шаблон:Cite web
  4. Шаблон:Cite web
  5. Шаблон:Cite web
  6. 6,0 6,1 Ошибка цитирования Неверный тег <ref>; для сносок CPPPL-46 не указан текст
  7. Шаблон:Книга
  8. ISO/IEC 14882:1998, раздел 6.4, пункт 4: «The value of a condition that is an initialized declaration in a statement other than a switch statement is the value of the declared variable implicitly converted to bool … The value of a condition that is an expression is the value of the expression, implicitly converted to bool for statements other than switch; if that conversion is ill-formed, the program is ill-formed».
  9. STLport: Welcome!
  10. The Java ™ Tutorials: The switch Statement
  11. MSDN: The switch statement in C#
  12. TIOBE Programming Community Index for January 2010
  13. Boehm-Demers-Weiser garbage collector for C and C++
  14. Шаблон:Статья
  15. Шаблон:Cite web
  16. Шаблон:Статья
  17. Шаблон:Cite web
  18. Шаблон:Cite web
  19. Шаблон:Cite web
  20. Class Arrays, JavaTM 2 Platform Std. Ed. v1.4.2
  21. The Java ™ Tutorials. A Closer Look at the «Hello World!» Application
  22. From "C++ Template Metaprogramming, " by David Abrahams and Aleksey Gurtovoy. Copyright (c) 2005 by Pearson
Advertisement