С++ обзор языка



страница4/10
Дата22.06.2019
Размер1.54 Mb.
1   2   3   4   5   6   7   8   9   10

6.6. Операторы перехода
Оператор перехода передает управление безусловно.
оператор-перехода:

break

continue

return выражение opt

goto идентификатор
При выходе из области действия вызываются деструкторы (12.4) для всех сконструируемых в области действия объектов, которые еще не были уничтожены к этому моменту. Это относится как к явно объявленным, так и временным объектам (12.2).
6.6.1. Оператор завешения (break)
Оператор может употребляться только в операторе цикла или операторе выбора и приводит к завершению наименьшего объемлющего оператора цикла или оператора выбора; управление передается оператору, следующему за завершенным.

Пример:
switch (val) {



case 1: f(); break;

case 2: g(); break;

default: h(); break;

}
6.6.2. Оператор продолжения (continue)
Оператор может употребляться только в операторе цикла и приводит к передаче управления на продолжающуюся часть цикла, т.е. на конец наименьшего повторяемого оператора. Более точно, в каждом из операторов
while (foo) { do { for (;;) {

// ... // ... // ...

contin: ; contin: ; contin: ;]

} } while (foo) }
оператор continue, если он не содержится во вложенном операторе цикла, эквивалентен goto contin. Пример:
while (cin) {

// . . .

if (cur_tok == PRINT) continue;

cout << expr() << '\n';

}

эквивалентно



while (cin) {

// . . .

if (cur_tok == PRINT) goto end_of-loop;

cout << expr() << '\n';

end_of-loop: ;

}
6.6.3. Оператор возврата (return)
Функция возвращает управление в точку вызова посредством оператора return. Оператор return без выражения можно употреблять только в функциях, возвращающих значение типа void, в конструкторах (12.1) и деструкторах (12.4).

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


6.6.4. Оператор перехода (goto)
Оператор передает управление оператору, помеченному указанным идентификатором. В программировании высокого уровня оператор имеет мало применений и его следует избегать. Одно из немногих разумных его применений состоит в выходе из вложенного цикла или переключателя (break прекращает выполнение только самого внутреннего охватывающего его цикла или переключателя). Пример:
void f()

{

int i;

int j;

for (int i = 0; i < n; i++)

for (int j = 0; j < m; j++)

if (nm[i][j] == a) goto found; // найдено

// не найдено

// . . .

found: // найдено

// nm[i][j] == a

}
6.7. Оператор-объявление
Оператор-объявление вводит в текущем блоке новый идентификатор.
оператор-объявление:

объявление


Если идентификатор, введенный объявлением, был ранее объявлен во внешнем блоке, внешнее объявление скрывается в оставшейся части блока и восстанавливается при выходе из него.
6.8. Разрешение неоднозначностей
Существует неоднозначность грамматики при выборе между оператором-выражением и объявлением. Оператор-выражение с явным приведением типа в функциональной записи (5.2.3) как самым левым подвыражением может оказаться неотличимым от объявления, первый описатель которого начинается с “(“. В этом случае оператор считается объявлением.
Чтобы снять неоднозначность, приходится иногда анализировать весь оператор. Это решает проблему во многих случаях. Предположим, например, что Т является именем-простого-типа (7.1.6), тогда:
T(a) -> m = 7; // оператор-выражение

T(a)++ // оператор-выражение

T(a, 5) << c; // оператор-выражение
T(*e) (int); // объявление

T(f)[] // объявление

T(g) = {1, 2}; // объявление

T(*d)(double(3)); // объявление
Прочие случаи являются объявлениями, например:
T(a); // объявление

T(*b)(); // объявление

T(c) = 7; // объявление

T(d), e, f = 3; // объявление

T(g)(h, 2); // объявление

7. Объявления
Объявления определяют смысл каждого идентификатора, но не всегда отводят память под него.
объявление:

decl-спецификаторы opt список-описателей opt;

asm-объявление

описание-функции

объявление-шаблона

спецификация-сборки


Описатели, составляющие список-описателей (8), содержат объявляемые идентификаторы. Decl-спецификаторы могут быть опущены только в описании (8.3) и объявлениии функции. Список-описателей может быть пуст только в объявлении класса (9) или перечисления (7.2), т.е. когда decl-спецификатор является спецификатором-класса или спецификатором-перечисления. Объявление имеет силу только в своей области действия (3.2). Примеры объявлений:
char ch;

int count = 1;

char* name = "Alex"

struct complex {float re, im};

complex cvar;

extern complex sqrt(complex);

extern int error-number;

typedef complex point;

float real (complex* p) {return p->re};

const double pi = 3.14159256358979932385;

struct user;

templete abs(T a) {return a<0 ? -a : a;};

enum beer {Carlsberg, Tuborg, Thor};
Как можно видеть из примеров, объявление может делать больше, чем ассоциировать тип с именем. Большинство определений являются также описаниями (определениями), т.е. они описывают сущность объявляемого имени. Для имен ch, count и cvar этой сущностью является соответсвующий объем памяти, используемый для хранения значения. Для имени real такой сущностью будет заданная функция. Для константы pi - это значение 3.14159256358979932385. Для имени complex - это новый тип. Наконец, для имени point - это тип complex, поэтому point становится синонимом complex. В рассматриваемом списке только объявления
extern complex sqrt(complex);

extern int error-number;

struct user;
не являются одновременно описаниями. Это означает, что объекты, которые они объявляют, будут описаны где-то еще. Тело функции sqrt должно задаваться неким другим объявлением, память для переменной error-number типа int должна выделяться неким другим объявлением, и некоторое другое объявление типа user должно описывать, что он из себя представляет.
Некоторые объявления задают "значения" для тех сущностей, которые они вводят:
int count = 1;

char* name = "Alex"

struct complex {float re, im};

typedef complex point;

float real (complex* p) {return p->re};

const double pi = 3.14159256358979932385;
Для типов, функций и констант "значение" неизменно, значение переменной может быть впоследствии изменено. Всякое объявление, задающее значение, является описанием.
7.1. Спецификаторы
decl-спецификаторы:

decl-спецификаторы opt decl-спецификатор

decl-спецификатор:

спецификатор-класса-памяти

спецификатор-типа

fct-спецификатор



template

friend

typedef
7.1.1. Спецификаторы класса памяти
спецификатор-класса-памяти:

auto

register

static

extern
Спецификаторы auto и register применимы только к именам объектов, объявленным в блоке (6.3) и формальным параметрам (8.3). Оба объявления вводят автоматический объект, который размещается каждый раз при входе в его блок и существует только до тех пор, пока из этого блока не вышли. Описатель auto почти всегда избыточен, одно из его полезных применений - задать явное отличие оператора-объявления от оператора-выражения (6.2). Пример: Компилятор знает, что

int (*p)[5]

является объявлением указателя на массив из пяти целых элементов, а украшение этого объявления спецификатором auto может лишь помочь восприятию читателя:



auto int (*p)[5]
Объявление register есть объявление auto, подсказывающее компилятору, что объявляемая переменная будет интенсивно использоваться.
Объявление объекта является описанием, если оно не содержит спецификатор extern или содержит инициализацию (3.1).
Описание вызывает отведение соответствующего количества памяти и соответствующую инициализацию (8.4).
Спецификаторы static и extern применимы только к именам объектов и функций. Имя, описанное как static имеет внутреннее связывание и живет только до конца программы, оно инициализируется только один раз, когда поток управления первый раз проходит через ее обявление. Пример:
int a = 1;

void f()

{

int b = 1; // инициализируется при каждом вызове f()

static int c = a; // инициализируется только один раз

. . .

};
int main()

{

while (a < 4) f();

}
Static-переменная без указанной инициализации неявно инициализируется нулем.
Когда переменные и функции явно объявлены как static на уровне файла, соответствующий фрагмент программы легче понимать (некуда больше заглядывать). Использование static для функций может, помимо этого, выгодно влиять на накладные расходы по вызову функции, поскольку задает компилятору более простую работу.
Имя, описанное как extern имеет внешнее связывание, кроме случая, когда оно ранее получило внутренне связывание. Примеры объявлений внешних имен:
extern complex sqrt(complex);

extern int error-number;
Имя, объявленное на уровне файла без спецификатора-класса-памяти, имеет внешнее связывание, если ему ранее не было придано внутреннее связывание или оно не объявлено как const.
Все объявления одного имени должны быть согласованы с типом объекта, к которому они относятся. Примеры:
static char* f(); // f() имеет внутреннее связывание

char*f() // f() все равно имеет внутреннее связывание

{ /* ... */}
char* g(); // g() имеет внешнее связывание

static char* g() // ошибка: не то связывание

{ /* ... */}
static int a; // “а” имеет внутреннее связывание

int a; // ошибка: два описания
static int b; // “b” имеет внутреннее связывание

extern int b // все равно внутреннее связывание
int c; // “с” имеет внешнее связывание

static int c; // ошибка: несоответствие связывания
extern int d; // “d” имеет внешнее связывание

static int d; // ошибка: несоответствие связывания
7.1.2. Спецификаторы функции
Некоторые спецификаторы можно употреблять только в объявлении функции.
fct-спецификатор:

inline

virtual
Спецификатор inline подсказывает компилятору, что открытая подстановка тела функции предпочтительнее обычной реализации вызова функции. Идентификатору функции при этом придается внутреннее связывание.
Спецификатор virtual можно употреблять только в объявлениях нестатических компонентных функций внутри объявления класса (10.2).
7.1.3. Описание имени типа
Объявления, содержащие typedef, вводят идентификаторы, используемые для именования основных или порожденных типов. Спецификатор typedef не может использоваться в описании-функции (8.3).
описанное-имя-типа:

идентификатор


Пример:

typedef complex point;

Здесь complex и point - описанные имена типов.


Внутри области действия объявления имени типа каждый идентификатор, являющийся частью описателя, становится синтаксически эквивалентным ключевому слову и именует тип, ассоциированный с этим идентификатором, способом, описанным в 8. Описанное-имя-типа становится таким образом синонимом другого типа. Оно не вводит новый тип в том смысле, в каком это делает объявление класса (9.1). Например, после объявления
typedef int MILES, *KLICKSP;
конструкции
MILES distance;

KLICKSP metricp;
верны; при этом distance имеет тип int, а metricp является указателем на int.
Описание имени типа не может переопределять имя типа, объявленное в этой же области действия, но именующее другой тип, например:
class complex { /* . . . */ }

typedef int complex; // ошибка: повторное описание
Описанное-имя-типа, именующее класс, является именем класса.
7.1.4. Спецификатор template
Спецификатор template применяется для определения семейств типов или функций (14).
7.1.5. Спецификатор friend
Спецификатор friend применяется дя спецификации доступа к компонентам класса (11.4).
7.1.6. Спецификаторы типа
спецификатор-типа:

имя-простого-типа

спецификатор-класса

спецификатор-перечисления

уточненный-спецификатор-типа

const

volatile
Ключевые слова const и volatile можно добавлять к любому правильному спецификатору-типа в объявлении объекта. Из числа других в объявление можно включать не более одного спецификатора типа.
Константный объект не может быть впоследствии изменен. Если он не объявлен явно как extern, он должен быть инициализирован и не имеет внешнего связывания. Примеры:
const int model = 90;

const int v[] = {1, 2, 3, 4};
Каждый элемент константного массива является константой. Каждый нефункциональный нестатический компонент константного класса также является константой (9.3.1).
Спецификатор const изменяет тип, т.е. ограничивает способ использования объекта. Поэтому, например, разумно и полезно описывать функцию, как возвращающую const. Пример:
const char* peek(int i) // возврат указателя на константу

{

return v[i];

}
У подвижных (volatile) объектов нет семантики, не зависящей от реализации; спецификатор volatile подсказывает компилятору, что тот должен избегать оптимизации действий над этим объектом, поскольку его значение может быть изменено скрытно от компилятора. Каждый элемент подвижного массива является подвижным. Каждый нефункциональный нестатический компонент подвижного класса также является подвижным (9.3.1).
Если спецификатор-типа в объявлении отсутствует, берется int.
имя-простого-типа:

полное-имя-класса

уточненое-имя-типа

char

short

int

long

signed

unsigned

float

double

void
Только один из спецификаторов short и long может быть скомбинирован с int. Каждый из них может появиться и сам по себе, в этом случае int подразумевается. Слово long может сочетаться с double. Одно из слов signed и unsigned можно комбинировать с char, short, int или long. Опять, каждый из них может появиться и сам по себе, в этом случае int подразумевается.
Спецификаторы-класса и спецификаторы-перечисления обсуждаются соответственно в 9 и 7.2.
уточненный-спецификатор-типа:

ключевое-слово-класса имя-класса

ключевое-слово-класса идентификатор

enum имя-перечисления
ключевое-слово-класса:

сlass

struct

union
Если задан идентификатор, уточненный-спецификатор-типа объявляет его именем-класса (9.1).
Имя, объявленное со спецификатором union, должно быть и описано как объединение. Имя, объявленное со спецификатором сlass, должно быть описано также со спецификатором сlass или struct. Имя, объявленное со спецификатором struct, должно быть описано также со спецификатором сlass или struct.
Имена вложенных типов (9.7) могут быть уточнены именем объемлещего класса:
уточненое-имя-типа:

описанное-имя-типа

имя-класса :: уточненое-имя-типа
полное-имя-класса:

уточненное-имя-класса

:: уточненное-имя-класса
уточненное-имя-класса:

имя-класса

имя-класса :: уточненное-имя-класса
Имя, уточненное именем-класса, должно быть типом, описанным в этом классе или в его базовом классе. Как обычно, имя, объявленное в производном классе, скрывает одноименные компоненты, описанные в базовых классах (3.2).
7.2. Объявление перечисления
Перечисление рассматривается как отдельный целочисленный тип (3.6.1) с поименованными константами. Его имя становится именем-перечисления, т.е. зарезервированным словом в своей области действия.
имя-перечисления:

идентификатор


спецификатор-перечисления:

enum идентификатор opt {список-перечисления opt}
список-перечисления:

элемент-перечисления

список-перечисления , элемент-перечисления
элемент-перечисления:

идентификатор



идентификатор = константное-выражение
Идентификаторы в списке-перечисления рассматриваются как константы и могут употребляться везде, где требуются константы. Если нет ни одного элемента-перечисления со знаком “=“, то значения соответствующих констант растут на единицу, начиная с нуля, при движении слева направо. Элемент-перечисления со знаком “=“ придает идентификатору указанное значение; последующие идентификаторы без “=“ продолжают прогрессию от присвоенного значения. Это значение должно быть целым или приводимым к целому посредством целочисленного расширения (4.1).
Имена элементов перечисления должны быть отличны от имен обычных переменных и других элементов перечисления с той же областью действия. Примеры:
enum color {red, orange, yellow, green, blue};
enum fruit {

apple,

pear,

orange, // ошибка: повторное описание orange”

kiwi };



enum bird {

emu,

dodo,

ostrich,

kiwi // ошибка: повторное описание kiwi

};
int emu; // ошибка: повторное описание emu
Значения элементов перечисления не обязаны быть различными. Значение элемента перечисления считается определенным сразу за его инициализатором. Например:
enum { a, b, c = 0 };

enum { d, e, f = e+2 };
определяет, что a, c и d равны 0, b и t равны 1, f равно 3.
Фактически перечисление определяет несколько целочисленных констант, которые могли бы быть определены и явным образом. Например,
enum { a, b, c = 0 };
эквивалентно
const int a = 0;

const int b = 1;

const int c = 0;
Каждое описание перечисления определяет новый целочисленный тип, отличный от всех других целочисленных типов. Значение элемента перечисления может быть преобразовано в целое при целочисленном расширении (4.1). Например:
enum color { red, yellow, green = 20, blue};

color col = red;

color* cp = &col;

if (*cp == blue) // . . .
Здесь возможными значениями объекта типа color являются red, yellow, green, blue; эти значения могут быть преобразованы в целые значения 0, 1, 20, 21. Однако, поскольку перечисления являются отдельными типами, объекту типа color может быть присвоено значение только типа color. Например:
color c = 1 // ошибка: несоответствие типов,

// нет преобразования от int к color

int i = yellow; // все верно: yellow преобразуется в целое 1

// посредством целочисленного расширения
Для преобразования целого в элемент перечисления необходимо указывать явное преобразование, например:
color c2 = color(1).
7.3. ASM объявления
Ассемблерное объявление имеет вид:
asm-объявление:

asm (литеральная-строка);
Семантика такого объявления определяется реализацией. Обычно оно служит для передачи информации через компилятор ассемблеру.
7.4. Спецификация сборки
Сборка (компоновка, редакция связей - linkage) фрагментов кода С++ с фрагментами на других языках программирования осуществляется посредством спецификации-сборки:
спецификация-сборки:

extern литеральная-строка { список-объявлений opt }

extern литеральная-строка объявление
список-объявлений:

объявление

список-объявлений объявление
Литеральная-строка задает нужный способ сборки; ее смысл определяется реализацией.

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

описатель-с-инициализацией

список-описателей, описатель-с-инициализацией
описатель-с-инициализацией:

описатель инициализатор opt


Двумя составляющими объявления (7.1) являются спецификаторы и описатели. Спецификаторы задают основной тип, класс памяти и другие характеристики объявляемых объектов и функций. Описатели определяют имена этих объектов и функций и, возможно, модифицируют их тип посредством таких операций как “*”(указатель на) и () (функция). Описатель может также задавать начальные значения (8.4, 12.6).
описатель:

d-имя


prt-операция описатель

описатель (список-объявлений-параметров) список-cv-описателей opt

описатель [константное-выражение opt]

(описатель)


prt-операция:

* список-cv-описателей opt

& список-cv-описателей opt

полное-имя-класса :: * список-cv-описателей opt


список-cv-описателей:

cv-описатель список-cv-описателей opt


cv-описатель:

const

volatile
d-имя:

имя


имя-класса

~ имя-класса

описанное-имя-типа

уточненное-имя-типа


Имя класса имеет особый смысл при объявлении класса с этим именем: а также при уточнении этим именем, т.е. в позиции левого операнда операции разрешения области действия “::” (12.1, 12.4).
8.1. Имена типов
Чтобы явно задать приведение значения или аргумент операций sizeof и new, нужно уметь назвать тип. Эту задачу выполняет имя-типа, которое синтаксически представляет собой как бы объявление объекта или функции этого типа без указания имени этого объекта или функции.
имя-типа:

список-спецификаторов-типа абстрактный-описатель opt


список-спецификаторов-типа:

спецификатор-типа список-спецификаторов-типа opt


абстрактный-описатель:

prt-операция абстрактный-описатель opt

абстрактный-описатель opt (список-объявлений-параметров) список-cv-описателей opt

абстрактный-описатель opt [константное-выражение opt]

(абстрактный-описатель)
Можно однозначно определить то место в абстрактном-описателе, где появился бы идентификатор, если бы конструкция была описателем в объявлении. Имя-типа именует тот самый тип, который был бы у гипотетического идентификатора. Например:
int // int i

int * // int *pi

int *[3] // int *p[3]

int (*)[3] // int (*p3i)[3]

int*() // int *f()

int (*)(double) // int (*pf)(double)
имеют соответственно типы “целое”, “указатель на целое”, “массив из трех указателей на целое”, “указатель на массив из трех целых”, “функция без параметров, возвращающая указатель на целое” и “указатель на функцию с параметром типа double и результатом целого типа”.




Поделитесь с Вашими друзьями:
1   2   3   4   5   6   7   8   9   10


База данных защищена авторским правом ©vossta.ru 2019
обратиться к администрации

    Главная страница