Не объектно-ориентированные возможности C++В этом разделе описываются возможности, непосредственно не связанные с объектно-ориентированным программированием (ООП). Многие из них, однако, особенно важны в сочетании с ООП. - Описатель inline означает, что функция является хорошим
кандидатом на оптимизацию, при которой в местах обращения к функции
компилятор вставит тело этой функции, а не код вызова. Пример: inline double Sqr(double x) {return x*x;}.
inline является не директивой, а рекомендацией компилятору — компилятор
не обязан реализовывать подстановку тела для inline-функций, но может,
исходя из заданных критериев оптимизации, выполнять подстановку тела
для функций, которые не объявлены как inline.
- Описатель volatile используется в описании переменных и
информирует компилятор, что значение данной переменной может быть
изменено способом, который компилятор не в состоянии отследить. Для
переменных, объявленных volatile, компилятор не должен применять
средства оптимизации, изменяющие положение переменной в памяти
(например, помещающие её в регистр) или полагающиеся на неизменность
значения переменной в промежутке между двумя присваиваниями ей значения.
- Вместо функций malloc и free (которые оставлены только для обратной совместимости), введены новые операции new и delete. Если T — произвольный тип, то
- new T выделяет память, достаточную для размещения одного объекта типа Т, возможно, инициализирует объект в этой памяти, и возвращает указатель типа Т*.
- new T[n] выделяет память, достаточную для размещения n
объектов типа Т, возможно, инициализирует каждый объект в этой памяти,
и возвращает указатель типа Т*.
- delete p — разрушает объект, на который ссылается указатель p, и освобождает область памяти, выделенную для него ранее операцией new T.
- delete [] p — разрушает каждый объект в массиве, на который
ссылается указатель p, и освобождает область памяти, выделенную для
этого массива ранее операцией new T[n].
Операция delete проверяет, что её аргумент не NULL, в противном случае она ничего не делает. При создании и удалении экземпляров классов с помощью new и delete компилятор генерирует вызовы конструктора и деструктора класса (см. ниже).
- Функции могут принимать аргументы по ссылке. Например, функция void f(int& x) {x=3;}
присваивает своему аргументу значение 3. Функции также могут возвращать
результат по ссылке, и ссылки могут быть вне всякой связи с функциями.
Например, {double&b=a[3]; b=sin(b);} эквивалентно a[3]=sin(a[3]);.
Ссылки в определённой степени сходны с указателями, со следующими
особенностями: при описании ссылки инициализируются указанием на
существующее значение данного типа; ссылка пожизненно указывает на один
и тот же адрес; при обращении к ссылке операция * производится автоматически. Существуют и другие отличия в использовании указателей и ссылок.
- Могут быть несколько функций с одним и тем же именем, но разными типами или количеством аргументов (перегрузка функций; при этом тип возвращаемого значения на перегрузку не влияет). Например, вполне можно писать:
void Print(int x); void Print(double x); void Print(int x, int y);
- Один или несколько последних аргументов функции могут задаваться по умолчанию. К примеру, если функция описана как void f(int x, int y=5, int z=10) , вызовы f(1), f(1,5) и f(1,5,10) эквивалентны.
- При описании функций отсутствие аргументов в скобках означает, в
отличие от Си, что аргументов нет, а не то, что они неизвестны. Если
аргументы неизвестны, надо пользоваться многоточием, например int printf(const char* fmt, …).
- Можно описывать операции над новыми типами. К примеру, так:
struct Date {int day, month, year;}; void operator ++(struct Date& date);
Операции ничем не отличаются от (других) функций. Нельзя описывать
операции над предопределёнными типами (скажем, переопределять умножение
чисел); нельзя выдумывать новые операции, которых нет в Си++ (скажем, **); арность (количество параметров) и приоритет операций сохраняется (скажем, в выражении a+b*c сначала будет выполняться умножение, а потом сложение, к каким бы типам ни принадлежали a, b и c.) Можно переопределить операции [] (с одним параметром) и () (с любым числом параметров).
- Добавлены пространства имён 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. Если мы в каком-то файле хотим обращаться к ним
непосредственно, мы можем написать
Или же
Пространства имён нужны, чтобы не возникало коллизий между пакетами,
имеющими совпадающие имена глобальных переменных, функций и типов.
Специальным случаем является безымянное пространство имён
Все имена, описанные в нём, доступны в текущей единице трансляции и больше нигде.
- Добавлен новый тип bool , имеющий значения true и false . Операции сравнения возвращают тип bool . Выражения в скобках после if , while приводятся к типу bool .
- // означает, что вся оставшаяся часть строки является комментарием.
- Добавлены шаблоны (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; - Введена стандартная библиотека шаблонов (STL,
Standard Template Library), определяющая шаблоны и функции для векторов
(одномерных массивов произвольной длины), множеств, ассоциативных
массивов (map), списков, символьных строк, потоков ввода-вывода и
другие шаблоны и функции.
- Если описана структура, класс, объединение (union) или перечисление (enum), её имя является именем типа, например:
struct Time { int hh, mm, ss; }; Time t1, t2;
- Внутри класса можно описывать вложенные типы, как через typedef,
так и через описание других классов, а также перечислений. Для доступа
к таким типам вне класса, к имени типа добавляется имя класса и два
двоеточия:
struct S { typedef int** T; T x; }; S::T y;
|