Развитие и стандартизация языка 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Развитие и стандартизация языка



История

Исторический этап развития[3] Год
Язык BCPL  
Язык Би (оригинальная разработка Томпсона под UNIX)  
Язык Си  
Си с классами  
C84  
Cfront (выпуск E)  
Cfront (выпуск 1.0)  
Множественное/виртуальное наследование  
Обобщённое программирование (шаблоны)  
ANSI C++ / ISO-C++  
ISO/IEC 14882:1998  
ISO/IEC 14882:2003  
C++/CLI  
TR1  
C++11  

Создание

Язык возник в начале 1980-х годов, когда сотрудник фирмы Bell Labs Бьёрн Страуструп придумал ряд усовершенствований к языку C под собственные нужды. [4] Когда в конце 1970-х Страуструп начал работать в Bell Labs над задачами теории очередей (в приложении к моделированию телефонных вызовов), он обнаружил, что попытки применения существующих в то время языков моделирования оказываются неэффективными, а применение высокоэффективных машинных языков слишком сложно из-за их ограниченной выразительности. Так, язык Симула имеет такие возможности, которые были бы очень полезны для разработки большого программного обеспечения, но работает слишком медленно, а язык BCPL достаточно быстр, но слишком близок к языкам низкого уровня и не подходит для разработки большого программного обеспечения.

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

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

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

До начала официальной стандартизации язык развивался в основном силами Страуструпа в ответ на запросы программистского сообщества. Функцию стандартных описаний языка выполняли написанные Страуструпом печатные работы по C++ (описание языка, справочное руководство и так далее). Лишь в 1998 году был ратифицирован международный стандарт языка C++: ISO/IEC 14882:1998 «Standard for the C++ Programming Language»; после принятия технических исправлений к стандарту в 2003 году — следующая версия этого стандарта — ISO/IEC 14882:2003.[5]

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

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

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

Общие принципы

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

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

Совместимость с языком С

Выбор именно C в качестве базы для создания нового языка программирования объясняется тем, что язык C:

1. является многоцелевым, лаконичным и относительно низкоуровневым языком;

2. подходит для решения большинства системных задач;

3. исполняется везде и на всём;

4. стыкуется со средой программирования UNIX.

— Б. Страуструп. Язык программирования C++. Раздел 1.6[8]

Несмотря на ряд известных недостатков языка C, Страуструп пошёл на его использование в качестве основы, так как «в C есть свои проблемы, но их имел бы и разработанный с нуля язык, а проблемы C нам известны». Кроме того, это позволило быстро получить прототип компилятора (cfront), который лишь выполнял трансляцию добавленных синтаксических элементов в оригинальный язык C.

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

  • сохранение действующего кода, написанного изначально на C и прямо перенесённого в C++;
  • исключение необходимости переучивания программистов, ранее изучавших C (им требуется только изучить новые средства C++);
  • исключение путаницы между языками при их совместном использовании («если два языка используются совместно, их различия должны быть или минимальными, или настолько большими, чтобы языки было невозможно перепутать»).

Обзор языка

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

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

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

Комментарии

С++ поддерживает как комментарии в стиле C:

/*

это комментарий, который может состоять

из нескольких строчек

*/

так и однострочные:

// вся оставшаяся часть строки является комментарием

где // обозначает начало комментария, а ближайший последующий символ новой строки, который не предварён символом \ (либо эквивалентным ему обозначением??/), считается окончанием комментария.

Типы

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

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

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

Функции могут принимать аргументы по ссылке. Например, функция 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, компилятор не должен применять средства оптимизации, изменяющие положение переменной в памяти (например, помещающие её в регистр) или полагающиеся на неизменность значения переменной в промежутке между двумя присваиваниями ей значения. В мультиядерной системе volatile помогает избегать барьеров памяти 2-го типа[ источник не указан 105 дней ].
  • Если описана структура, класс, объединение (union) или перечисление (enum), её имя является именем типа, например:

struct Time {

int hh, mm, ss;

};

Time t1, t2;

  • Добавлены пространства имён (namespace). Например, если написать

namespace Foo

{

const int x=5;

typedef int** T;

void f(int 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 проверяет, что её аргумент не является нулевым указателем, в противном случае она ничего не делает. Для инициализации объекта non-POD классового типа new-выражение вызывает конструктор; для уничтожения объекта классового типа delete-выражение вызывает деструктор (см. ниже).

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

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

class Array

{

...

inline double operator[] (int n) const;

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

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

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

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

Наследование бывает публичным, защищённым и закрытым (то есть закрытого типа):

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

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

Полиморфизм

Семантика системы типов С++ не полиморфна (в отличие от потомков ML, в том числе гибридных с Си — BitC, Cyclone), однако есть несколько способов обеспечить полиморфное поведение. Прежде всего это перегрузка методов классов при наследовании — традиционный для ООП способ обеспечения абстракции данных. Затем есть два способа реализации параметрического полиморфизма (в С++-сообществе обычно называемого «обобщённым программированием»). Первый способ наследован из Си — использование бестипового указателя и приведение типа в зависимости от других данных — хотя в С++ этот способ традиционно считается неидеоматичным и опасным. Второй заключается в использовании шаблонов — но, в отличие от обычных реализаций параметрического полиморфизма, в С++ происходит автоматическая генерация семейства перегруженных мономорфных функций на основании полиморфного определения (шаблона) в соответствии с контекстами его использования — то есть параметрический полиморфизм на уровне исходного кода транслируется в ситуативный (ad hoc) на уровне машинного, за что С++ подвергается критике (см. раздел Вычислительная производительность). В С++ также есть третий вид перегрузки — Перегрузка операторов — которая в сочетании с наследованием классов предоставляет ещё большие возможности повышения читабельности кода путём ввода т. н. «синтаксического сахара».

Для обеспечения абстракции данных необходимо связать несколько классов в иерархию наследования и назначить функциям одинаковые спецификации. Например:

class Figure

{

...

void Draw() const;

...

};

 

class Square: public Figure

{

...

void Draw() const;

...

};

 

class Circle: public Figure

{

...

void Draw() const;

...

};

 

class Window

{

...

void Draw() const;

...

};

 

class SquareWindow: public Window

{

...

void Draw() const;

...

};

 

class RoundWindow: public Window

{

...

void Draw() const;

...

};

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

Circle *c = new Circle(0,0,5);

Figure *f = c; // правильно: Figure — базовый класс для Circle

c->Draw();

f->Draw(); // Указатели равны друг другу, но для f и c будут вызваны разные функции

SquareWindow *sw = new SquareWindow(0,0,5);

sw->Draw(); // используется так же

f = sw; // ошибка! SquareWindow не входит в число наследников Figure!

Как видно, диапазон этого вида полиморфизма в С++ ограничивается на этапе проектирования заданным перечнем типов. По умолчанию такой полиморфизм является статическим, но при использовании спецификатора virtual он превращается в динамический (см. позднее связывание):

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;

);

Чистая виртуальная функция не имеет определения и не может быть непосредственно вызвана. Цель объявления такой функции — создать в общем базовом классе сигнатуру-прототип, которая не имела бы собственного определения, но позволяла создавать такие определения в классах-потомках и вызывать их через указатель на общий базовый класс. Функция-член объявляется чистой виртуальной тогда, когда её определение для базового класса не имеет смысла. Так, в вышеприведённом примере для базового класса Figure определение функции Draw() не имеет смысла, так как «фигур вообще» не бывает и их невозможно отобразить, но описание такой функции необходимо, чтобы можно было её переопределить в классах-потомках и вызывать методы Draw этих классов через указатель на Figure. Следовательно, вполне логично объявить Figure.Draw() как чистую виртуальную функцию-член.

С понятием чистой виртуальной функции в C++ тесно связано понятие «абстрактный класс». Абстрактным классом называется такой, у которого есть хотя бы одна не переопределённая чистая виртуальная функция-член. Экземпляры таких классов создавать запрещено, абстрактные классы могут использоваться только для порождения новых классов путём наследования. Если в классе-потомке абстрактного класса не переопределены все унаследованные чистые виртуальные функции, то такой класс также является абстрактным и на него распространяются все указанные ограничения.

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

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

Основным способом организации информации в 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 const double & Elem(int i) const

{

return val[i];

}

 

inline void ChangeElem(int i, double x)

{

val[i] = x;

}

 

protected:

void Alloc(int _len)

{

if (len == 0)

Free();

 

len = _len;

val = new double[len];

}

 

void Free()

{

delete [] val;

len = 0;

}

 

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 как друг, то все собственные (не унаследованные) функции-члены класса A могут обращаться к любым членам класса B. Например:

class Matrix {

...

friend class Vector::getNum(Matrix &);

...

private:

int i;

};

...

class Vector

{

int GetNum(Matrix & m){ return m.i;} //обращение к закрытому члену данных класса Matrix

};

Пример обращения:

void SomeFunction()

{

Matrix m;

Vector v;

 

int i = Vector::GetNum(m);

}

Четыре важных ограничения, накладываемых на отношения дружественности в C++:

  • Дружественность не транзитивна. Если A объявляет другом B, а B, в свою очередь, объявляет другом C, то C не становится автоматически другом для A. Для этого A должен явно объявить C своим другом.
  • Дружественность не взаимна. Если класс A объявляет другом класс B, то он не становится автоматически другом для B. Для этого должно существовать явное объявление дружественности A в классе B.
  • Дружественность не наследуется. Если A объявляет класс B своим другом, то потомки B не становятся автоматически друзьями A. Для этого каждый из них должен быть объявлен другом A в явной форме.
  • Дружественность не распространяется на потомков. Если класс A объявляет B другом, то B не становится автоматически другом для классов-потомков A. Каждый потомок, если это нужно, должен объявить B своим другом самостоятельно.

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

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

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

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

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

Конструкторы обозначаются как одноимённые классу функции (например, 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; // вызывается Array::Array(const Array&)

b=c; // происходит вызов оператора =

// если он не определён (как в данном случае), то вызывается сгенерированный компилятором оператор присваивания, который

// осуществляет копирование базовых подобъектов и почленное копирование нестатических членов-данных.

// как правило конструктор копий и оператор присваивания переопределяются попарно

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

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

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

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

class Array {

...

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

И далее

Array a(10);

...

double b = a[5];

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

Общая структура

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

Доступ к возможностям стандартной библиотеки C++ обеспечивается с помощью включения в программу (посредством директивы #include) соответствующих стандартных заголовочных файлов. Всего в стандарте C++11 определено 79 таких файлов. Средства стандартной библиотеки объявляются как входящие в пространство имён std. Заголовочные файлы, имена которых соответствуют шаблону «cX», где X — имя заголовочного файла стандартной библиотеки C без расширения (cstdlib, cstring, cstdio и пр.), содержат определения, соответствующие данной части стандартной библиотеки C, при этом программист может воспользоваться заголовочными файлами с именами по шаблону «cX.h» (добавлено стандартное расширение заголовочных файлов C «.h»), в которых те же средства определены как относящиеся к глобальному пространству имён.

Для использования следующих функций стандартной библиотеки

void* operator new(std::size_t) throw(std::bad_alloc);

void* operator new[](std::size_t) throw(std::bad_alloc);

void operator delete(void*) throw();

void operator delete[](void*) throw();

подключение каких-либо заголовочных файлов не требуется.

Состав

Стандартная библиотека включает в себя следующие разделы:

  • Поддержка языка. Включает средства, которые необходимы для работы программ, а также сведения об особенностях реализации. Выделение памяти, RTTI, базовые исключения, пределы значений для числовых типов данных, базовые средства взаимодействия со средой, такие как системные часы, обработка сигналов UNIX, завершение программы.
  • Стандартные контейнеры. В стандартную библиотеку входят шаблоны для следующих контейнеров: одномерные массивы, списки, одно- и двунаправленные очереди, стеки, ассоциативные массивы, множества, очереди с приоритетом.
  • Основные утилиты. В этот раздел входит описание основных базовых элементов, применяемых в стандартной библиотеке, распределителей памяти и поддержка времени и даты в стиле C.
  • Итераторы. Обеспечивают шаблоны итераторов, с помощью которых в стандартной библиотеке реализуется стандартный механизм группового применения алгоритмов обработки данных к элементам контейнеров.
  • Алгоритмы. Шаблоны для описания операций обработки, которые с помощью механизмов стандартной библиотеки могут применяться к любой последовательности элементов, в том числе к элементам в контейнерах. Также в этот раздел входят описания функций bsearch() и qsort() из стандартной библиотеки C.
  • Строки. Шаблоны строк в стиле C++. Также в этот раздел попадает часть библиотек для работы со строками и символами в стиле C.
  • Ввод/вывод. Шаблоны и вспомогательные классы для потоков ввода/вывода общего вида, строкового ввода/вывода, манипуляторы (средства управления форматом потокового ввода/вывода в стиле C++).
  • Локализация. Определения, используемые для поддержки национальных особенностей и форматов представления (дат, валют и т. д.) в стиле C++ и в стиле C.
  • Диагностика. Определения ряда исключений и механизмов проверки утверждений во время выполнения (assert). Поддержка обработки ошибок в стиле C.
  • Числа. Определения для работы с комплексными числами, математическими векторами, поддержка общих математических функций, генератор случайных чисел.

Контейнеры, строки, алгоритмы, итераторы и основные утилиты, за исключением заимствований из библиотеки C, собирательно называются STL (Stanard Template Library — стандартная шаблонная библиотека). Изначально эта библиотека была отдельным продуктом и её аббревиатура расшифровывалась иначе, но потом она вошла в стандартную библиотеку C++ в качестве неотъемлемого элемента. В названии отражено то, что для реализации средств общего вида (контейнеров, строк, алгоритмов) использованы механизмы обобщённого программирования (шаблоны C++ — template). В работах Страуструпа подробно описываются причины, по которым был сделан именно такой выбор. Основными из них являются бо́льшая универсальность выбранного решения (шаблонные контейнеры, в отличие от объектных, могут легко использоваться для не объектных типов и не требуют наличия общего предка у типов элементов) и его техническая эффективность (как правило, операции шаблонного контейнера не требуют вызовов виртуальных функций и могут легко встраиваться (inline), что в итоге даёт столь же производительный код, как и при ручном кодировании).

Реализации

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

Проект под названием STLport[10], основанный на SGI STL, осуществляет постоянное обновление STL, IOstream и строковых классов. Некоторые другие проекты также занимаются разработкой частных применений стандартной библиотеки.

Отличия от языка C

Новые возможности

Имеется викиучебник по теме
«Основные отличия C++ от C»

Нововведениями C++ в сравнении с C являются:



Поделиться:


Последнее изменение этой страницы: 2016-12-12; просмотров: 481; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.118.120.109 (0.248 с.)