Купить
 
 
Жанр: Учеба

Язык С++ с комментариями

страница №21

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

int x[] = { 1, 3, 5 };

описывает и инициализирует x как одномерный массив, имеющий три
члена, поскольку размер не был указан и дано три инициализатора.
____________________
* В английском "garbage", означающее затертое место [памяти],
т.е. если переменная целая, то 0, если char, то '\0', если
указатель на Т, то (Т*) NULL.

- стр 292 -

float y[4][3] =
{
{ 1, 3, 5 },
{ 2, 4, 6 },
{ 3, 5, 7 }
};

является полностью снабженной квадратными скобками инициализацией:
1,3 и 5 инициализируют первый ряд массива y[0], а именно, y[0][2].
Аналогично, следующие две строки инициализируют y[1] и y[2].
Инициализатор заканчивается раньше, поэтому y[3] инициализируется
значением 0. В точности тот же эффект может быть достигнут с
помощью

float y[4][3] =
{
1, 3, 5, 2, 4, 6, 3, 5, 7
};

Инициализатор для y начинается с левой фигурной скобки, но не
начинается с нее инициализатор для y[0], поэтому используется три
значения из списка. Аналогично, следующие три успешно используются
для y[1] и следующие три для y[2].

float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } };

инициализирует первый столбец y (рассматриваемого как двумерный
массив) и оставляет остальные элементы нулями.

8.6.2 Классовые объекты

Объект с закрытыми членами не может быть инициализован с помщью
простого присваивания, как это описывалось выше; это же относится к
объекту объединение. Если класс имеет конструктор, не получающий
значений, то этот конструктор используется для объектов, которые
явно не инициализированы.
Параметры для конструктора могут также быть представлены в виде
заключенного в круглые скобки списка. Например:

struct complex
{
float re;
float im;
complex (float r,float i) { re=r; im=i; }
complex (float r) { re=r; im=0; }
};

complex zz (1,2.3);
complex* zp = new complex (1,2.3);

Инициализация может быть также выполнена с помощью явного
присваивания; преобразования производятся. Например,

- стр 293 -

complex zz1 = complex (1,2.3);
complex zz2 = complex (123);
complex zz3 = 123;
complex zz4 = zz3;

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

8.6.3 Ссылки

Когда переменная описана как T&, что есть "ссылка на тип T", она
может быть инициализирована или указателем на тип T, или объектом
типа T. В последнем случае будет неявно применена операция взятия
адреса &. Например:

int i;
int& r1 = i;
int& r2 = &i;

И r1 и r2 будут указывать на i.
Обработка инициализации ссылки очень сильно зависит от того, что
ей присваивается. Как описывалось в #7.1, ссылка неявно
переадресуется при ее использовании. Например

r1 = r2;

означает копирование целого, на которое указывает r2, в целое, на
которое указывает r1.
Ссылка должна быть инициализована. Таким образом, ссылку можно
считать именем объекта.
Чтобы получить указатель pp, обозначающий тот обект, что и ссылка
rr, можно написать pp=&rr. Это будет проинтерпретировано как
pp=&*rr.
Если инициализатор для ссылки на тип T не является адресным
выражением, то будет создан и инициализован с помощью правил
инициализации объект типа T. Тогда значением ссылки станет адрес
объекта. Время жизни объекта, созданного таким способом, будет в
той области видимости, в которой он создан. Например:

double& rr = 1;

допустимо, и rr будет указывать на объект типа double, в котором
хранится значение 1.0.
Ссылки особенно полезны в качестве типов параметров.

- стр 294 -

8.6.4 Массивы символов

Последняя сокращенная запись позволяет инициализировать строкой
массив данных типа char. В этом случае последовательные символы
строки инициализируют члены массива. Например:

char msg[] = "Syntax error on line %d\n";

демонстрирует массив символов, члены которого инициализированы
строкой.

8.7 Имена типов

Иногда (для неявного задания преобразования типов и в качестве
параметра sizeof или new) нужно использовать имя типа данных. Это
выполняется при помощи "имени типа" которое по сути является
описанием для объекта этого типа, в котором опущено имя объекта.

имя_типа:
спецификатор_типа абстрактный_описатель
абстрактный_описатель :
пустой
* абстрактный_описатель
абстрактный_описатель ( списоко_писателей_параметров)
абстрактный_описатель [ константное_выражение opt ]
( абстрактный_описатель )
Является возможным идентифицировать положение в
абстрактном_описателе, где должен был бы появляться идентификатор в
случае, если бы конструкция была описателем в описании. Тогда
именованный тип является тем же, что и тип предполагаемого
идентификатора. Например:

int
int *
int *[3]
int *()
int (*)()

именует, соответсвенно, типы "целое", "указатель на целое",
"указатель на массив из трех целых", "функция, возвращающая
указатель на функцию, возвращающую целое" и "указатель на целое".
Простое имя типа есть имя типа, состоящее из одного
идентификатора или ключевого слова.
простое_имя_типа:
typedef-имя
char
short
int
long
unsigned
float
double
Они используются в альтернативном синтаксисе для преобразования
типов. Например:

- стр 295 -

(double) a

может быть также записано как

double (a)

8.8 Определение типа typedef

Описания, содержащие спецификатор_описания typedef, определяют
идентификаторы, которы позднее могут использоваться так, как если
бы они были ключевыми словами типа, именующее основные или
производные типы.
typedef-имя:
идентификатор
Внутри области видимости описания, содержащего typedef, каждый
идентификатор, возникающий как часть какого-либо описателя,
становится в этом месте синтаксически эквивалентным ключевому слову
типа, которое именует тип, ассоциированный с идентификатором таким
обрахом, как описывается в #8.4. Имя класса или перечисления также
является typedef-именем. Например, после

typedef int MILES, *KLICKSP;
struct complex { double re, im; };

каждая из конструкций

MILES distance;
extern KLICKSP metricp;
complex z, *zp;

является допустимым описанием; distance имеет тип int, metricp
имеет тип "указатель на int".
typedef не вводит новых типов, но только синонимы для типов,
которые могли бы быть определены другим путем. Так в приведенном
выше примере distance рассматривается как имеющаяя в точности тот
же тип, что и любой другой int объект.

Но описание класса вводит новый тип. Например:

struct X { int a; };
struct Y { int a; };
X a1;
Y a2;
int a3;

описывает три переменных трех различных типов.
Описание вида
описание_имени:
агрег идентификатор ;
enum идентификатор ;
определяет то, что идентификатор является именем некоторого
(возможно, еще не определенного) класса или перечисления. Такие
описания позволяют описывать классы, ссылающихся друг на друга.
Например:

- стр 296 -

class vector;
class matrix
{
friend matrix operator* (matrix&,vector&);
};

class vector
{
friend matrix operator* (matrix&,vector&);
};

8.9 Перегруженные имена функций

В тех случаях, когда для одного имени определено несколько
(различных) описаний функций, это имя называется перегруженным. При
использовании этого имени правильная функция выбирается с помощью
сравнения типов фактических параметров с типами параметров в
описаниях функций. К перегруженным именам неприменима операция
получения адреса &.
Из обычных арифметических преобразований, определенных в #6.6,
для вызова перегруженной функции выполняются только
char-"short-"int, int-"double, int-"long и float-"double. Для того,
чтобы перегрузить имя функции не-члена описание overload должно
предшествовать любому описанию функции; см. #8.2.
Например:

overload abs;
int abs (int);
double abs (double);

Когда вызывается перегруженное имя, по порядку производится
сканирование списка функций для нахождения той, которая может быть
вызвана. Например, abs(12) вызывает abs(int), а abs(12.0) будет
вызывать abs(double). Если бы был зарезервирован порядок вызова, то
оба обращения вызвали бы abs(double).
Если в случае вызова перегруженного имени с помощью
вышеуказанного метода не найдено ниодной функции, и если функция
получает параметр типа класса, то констукторы классов параметров (в
этом случае существует единственный набор преобразований, делающий
вызов допустимым) применяются неявным образом. Например:

class X { ... X (int); };
class Y { ... Y (int); };
class Z { ... Z (char*); };

overload int f (X), f (Y);
overload int g (X), g (Y);

f (1); /* неверно: неоднозначность f(X(1)) или f(Y(1)) */
g (1); /* g(X(1)) */
g ("asdf"); /* g(Z("asdf")) */

- стр 297 -

Все имена функций операций являются автомаатически
перегруженными.


8.10 Описание перечисления

Перечисления являются int с именованными константами.
enum_спецификатор:
enum идентификатор opt { enum_список }

enum_список:
перечислитель
enum_список, перечислитель

перечислитель:
идентификатор
идентификатор = константное_выражение
Идентификаторы в enum-списке описаны как константы и могут
появляться во всех местах, где требуются константы. Если не
появляется ни одного перечислителя с =, то значения всех
соответствующих констант начинаются с 0 и возрастают на 1 по мере
чтения описания слева нарпаво. Перечислитель с = дает
ассоциированному с ним идентификатору указанное значение;
последующие идентификаторы продолжают прогрессию от присвоеннного
зеначения.
Имена перечислителей должны быть отличными от имен обычных
переменных. Значения перечислителей не обязательно должны быть
различными.
Роль идентификатора в спецификаторе перечисления
enum_спецификатор полностью аналогична роли имени класса; он
именует определенный нутератор. Например:

enum color { chartreuse, burgundy, claret=20, winedark };
color *cp, col;
col = claret;
cp = &col;
if (*cp == burgundy) ...

делает color именем типа,описывающего различные цвета, и затем
описывает cp как указатель на объект этого типа. Возможные значения
извлекаются из множества { 0, 1, 20, 21 }.

8.11 Описание Asm

Описание Asm имеет вид
asm (строка);
Смысл описания asm неопределен. Обычно оно используется для
передачи информации ассемблеру через компилятор.

- стр 298 -

9. ОПЕРАТОРЫ

Операторы выполняются последовательно во всех случаях кроме особо
оговоренных.

9.1 Оператор выражение

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

9.2 Составной оператор, или блок

Составной оператор (называемый также "блок", что эквивалентно)
дает возможность использовать несколько операторов в том месте, где
предполагается использование одного:
составной_оператор:
{ список_описаний opt список_операторов opt }
список_описаний:
описание
описание список_описаний
список_операторов:
оператор
оператор список_операторов
Если какой-либо из идентификаторов в списке_описаний был ранее
описан, то внешенее описание выталкивается на время выполнения
блока, и снова входит в силу по его окончании.

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

9.3 Условный оператор

Есть два вида условных операторов
if ( выражение ) оператор
if ( выражение ) оператор else оператор
В обоих случаях вычисляется выражение, и если оно не ноль, то
выполняется первый подоператор. Во втором случае второй подоператор
выполняется, если выражение есть 0. Как обычно, неоднозначность
"else" разрешается посредством того, что else связывается с
последним встречнным if, не имеющим else.

9.4 Оператор while

Оператор while имеет вид
while ( выражение ) оператор

- стр 299 -

Выполнение подоператора повторяется, пока значение выражения
остается ненулевым. Проверка выполняется передкаждым выполнением
оператора.

9.5 Оператор do

Оператор do имеет вид
do оператор while (выражение);
Выполнение подоператора повторяется до тех пор, пока значение
выражения не станет нулем. Проверка выполняется после каждого
выполнения оператора.

9.6 Оператор for

Оператор for имеет вид
for ( выражение_1 opt ; выражение_2 opt ; выражение_3 opt )
оператор
Этот оператор эквивалентен следующему:

- стр 300 -

выражение_1;
while (выражение_2)
{
оператор
выражение_3;
}
Первое выражение задает инициализацию цикла; второе выражение
задает осуществляемую перед каждой итерацией проверку, по которой
производится выход из цикла, если выражение становится нулем;
третье выражение часто задает приращение, выполняемое после каждой
итерации.
Каждое или все выражения могут быть опущены. Отсутствие
выражения_2 делает подразумеваемое while-предложение эквивалентым
while(1); остальные опущенные выражения просто пропускаются в
описанном выше расширении.

9.7 Оператор switch

Оператор switch вызывает передачу управления на один из
нескольких операторов в зависимости от значения выражения. Он имеет
вид
switch ( выражение ) оператор
Выражение должно быть целого типа или типа указателя. Любой
оператор внутри оператора может быть помечен одним или более
префиксом case следующим образом:
case константное_выражение :
где константное выражение должно иметь тот же тип что и выоажениепереключатель;
производятся обычные арифметические преобразования.
В одном операторе switch никакие две константы, помеченные case, не
могут иметь одинаковое значение. Константные выражения точно
определяются в #15.

Может также быть не более чем один префикс оператора вида
default :
Когда выполнен оператор switch, проведено вычисление его
выражения и сравнение его с каждой case константой. Если одна из
констант равна значению выражения, то управление передается на
выражение, следующее за подошедшим префиксом case. Если никакая
case константа не соответствует выражению, и есть префикс default,
то управление передается на выражение, которому он предшествует.
Если нет соответсвующих вариантов case и default отсутствует, то
никакой из операторов в операторе switch не выполняется.
Префиксы case и default сами по себе не изменяют поток
управления, который после задерки идет дальше, перескакивая через
эти префиксы. Для выхода из switch см. break, #9.8.
Обычно зависящий от switch оператор является составным. В голове
этого оператора могут стоять описания, но инициализации
автоматических и регистровых переменных являются безрезультатными.

9.8 Оператор break

Оператор
break ;

- стр 301 -

прекращает выполнение ближайшего охватывающего while, do, for или
switch оператора; управление передается на оператор, следующий за
законченным.

9.9 Оператор continue

Оператор
continue ;
вызывает передачу управления на управляющую продолжением цикла
часть наименьшего охватывающего оператора while, do или for; то
есть на конец петли цикла. Точнее, в каждом из операторов

while (...) do for (...)
{ { {
contin:; contin:; contin:;
} } }
while (...);

continue эквивалентно goto contin. (За contin: следует пустой
оператор, #9.13.)

9.10 Оператор return

Возврат из функции в вызывающеую программу осуществляется с
помощью оператора return, имеющего один из двух видов:
return ;
return выражение ;
Первый может использоваться только в функциях, не возвращающих
значения, т.е. в функциях с типом возвращаемого значения void.
Вторая форма может использоваться только в функциях, не
возвращающих значение; вызывающей функцию программе возвращается
значение выражения. Если необходимо, то выражение преобразуется,
как это делается при присваивании, к типу функции, в которой оно
возникло. Обход конца функции эквивалентен возврату return без
возвращаемого значения.

9.11 Оператор goto

Можно осуществлять безусловную передачу упраления с помощью
оператора
goto идентификатор ;
Идентификатор должен быть меткой (#9.12), расположенной в
текущей функции.

9.12 Помеченные операторы

Перед любым оперотором может стоять префикс метка, имеющий вид
идентификатор :
который служит для описания идентификатора как метки. Метка
используется только как объект для goto. Областью видимости метки

- стр 302 -

является текущая функция, исключая любой подблок, в котором был
переописан такой же идентияикатор. См. #4.1.

9.13 Пустой оператор

Пустой оператор имеет вид
;
Пустой оператор используется для помещения метки непосредственно
перед } составного оператора или того, чтобы снабдить такие
операторы, как while, пустым телом.

9.14 Оператор delete

Оператор delete имеет вид
delete выражение ;
Результатом выражения должен быть указатель. Объект, на который
он указывает, уничтожается. Это значит, что после оператора
уничтожения delete нельзя гарантировать, что объект имеет
определенное значение; см. #17. Эффект от применеия delete к
указателю, не полученному из операции new (#7.1), неопределен.
Однако, уничтожение указателя с нулевым значением безопасно.

9.15 Оператор asm

Оператор asm имеет вид
asm ( строка) ;
Смысл оператора asm неопределен. Обычно он используется для
передачи информации черз компилятор ассемблеру.

10. ВНЕШНИЕ ОПРЕДЕЛЕНИЯ

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

10.1 Определения функций

Определения функций имеют вид
определение_функции:
спецификаторы_описания описатель_функции opt инициализа-
тор_базового_класса opt
тело_функции
Единственными спецификаторами класса памяти (sc-спецификаторами),
допустимыми среди спецификаторов описания, являются extern,

- стр 303 -

static, overload, inline и virtual. Описатель функции похож на
описатель "функции, возвращающей ...", за исключением того, что он
включает в себя имена формальных параметров определяемой функции.
Описатель функции имеет вид
описатель_функции:
описатель ( список_описаний_параметров )
Форма списка описаний параметров определена в #8.4. Единственный
класс памяти, который может быть задан, это тот, при котором
соответствующий фактический параметр будет скопирован, если это
возможно, в регистр при входе в функцию. Если в качестве
инициализатора для параметра задано константное выражение, то это
значение используется как значение параметра по умолчанию.
Тело функции имеет вид
тело_функции:
составной_оператор
Вот простой пример полного определения функции:

int max (int a,int b,int c)
{
int m = (a " b) ? a : b;
return (m " c) ? m : c;
}

Здесь int является спецификатором типа ; max (int a, int b, int
c) является описателем функции ; { ... } - блок, задающий текст
программы (код) оператора.
Поскольку в контексте выражения имя (точнее, имя как формальный
параметр) считается означающим указатель на первый элемент массива,
то описания формальных параметров, описанных как "массив из ...",
корректируются так, чтобы читалось "указатель на ...".
Инициализатор базового класса имеет вид
инициализатор_базового_класса:
: ( список_параметров opt )
Он используется для задания параметров конструктора базового
класса в конструкторе производного класса. Например:

struct base { base (int); ... };
struct derived : base { derived (int); ... };

derived.derived (int a) : (a+1) { ... }

derived d (10);

Конструктор базового класса вызывается для объекта d с параметром
11.

10.2 Определения внешних данных

Определения внешних данных имеют вид
определение_данных:
описание
Класс памяти таких данных статический.
Если есть более одного определения внешних данных одного именеи,
то определения должны точно согласовываться по типу и классу

- стр 304 -

памяти, и инициализаторы (если они есть), должны иметь одинаковое
значение.

11. ПРАВИЛА ОБЛАСТИ ВИДИМОСТИ

См. #4.1.

12. КОМАНДНЫЕ СТРОКИ КОМПИЛЯТОРА

Компилятор языка C++ содержит препроцессор, способный выполнять
макроподстановки, условную компиляцию и включение именованных
файлов. Строки, начинающиеся с #, относятся к препроцессору. Эти
строки имеют независимый от остального языка синтаксис; они могут
появляться в любом месте оказывать влияние, которое
распространяется (независимо от области видимости) до конца
исходного файла программы.
Заметьте, что определения const и inline дают альтернативы для
большинства использований #define.

12.1 Замена идентификаторов

Командная строка компилятора имеет вид
#define идент строка_символов
вызывает замену препроцессором последующих вхождений
идентификатора, заданного строкой символов. Точка с запятой внутри
(или в конце) строки символов является частью этой строки.
Строка вида
#define идент( идент , ..., идент ) строка_символов
где отсутсвует пробел между первым идентификатором и (, является
макроопределением с параметрами. Последующие вхождения первого
идентификатора с идущими за ним (, последовательностью символов,
разграниченной запятыми, и ), заменяются строкой символов, заданной
в определении. Каждое местоположение идентификатора, замеченного в
списке параметров определения, заменяется соответствующей строкой
из вызова. Фактическими параметрами вызова являются строки
символов, разделенные запятыми; однако запятые в строке,
заключенной в кавычки, или в круглых скобках не являются
разделителями параметров. Число формальных и фактических параметров
должно совпадать. Строки и символьные константы в символьной строке
сканируются в поисках формальных параметров, но строки и символьные
константы в остальной программе не сканируются в поисках
определенных (с помощью define) идентификаторов.

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

- стр 305 -

12.2 Включение файлов

Командная строка компилятора вида
#include "имя_файла"
вызывает замену этой строки полным содержимым файла

Список страниц

Закладка в соц.сетях

Купить

☏ Заказ рекламы: +3805044-68-872

© Ассоциация электронных библиотек Украины

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