Операторы выполняются последовательно во всех случаях кроме особо оговоренных.
Большинство операторов является операторами выражение, которые
имеют вид выражение ;
Обычно операторы выражение являются присваиваниями и вызовами
функций.
Составной оператор (называемый также "блок", что эквивалентно) дает возможность использовать несколько операторов в том месте, где предполагается использование одного:
составной_оператор: { список_описаний opt список_операторов opt } список_описаний: описание описание список_описаний список_операторов: оператор оператор список_операторов
Есть два вида условных операторов
if ( выражение ) оператор if ( выражение ) оператор else оператор
Оператор while имеет вид
while ( выражение ) оператор
Оператор do имеет вид
do оператор while (выражение);
Оператор for имеет вид
for ( выражение_1 opt ; выражение_2 opt ; выражение_3 opt ) оператор
выражение_1; while (выражение_2) { оператор выражение_3; }
Оператор switch вызывает передачу управления на один из нескольких операторов в зависимости от значения выражения. Он имеет вид
switch ( выражение ) оператор
case константное_выражение :
default :
Оператор
break ;
Оператор
continue ;
while (...) | do | for (...) |
{ | { | { |
... | ... | ... |
contin:; | contin:; | contin:; |
} | } | } |
while (...); |
Возврат из функции в вызывающую программу осуществляется с помощью оператора return, имеющего один из двух видов:
return ; return выражение ;
Можно осуществлять безусловную передачу управления с помощью оператора
goto идентификатор ;
Перед любым оператором может стоять префикс метка, имеющий вид
идентификатор :
Пустой оператор имеет вид
;
Оператор delete имеет вид
delete выражение ;
Оператор asm имеет вид
asm ( строка) ;
Программа на C++ состоит из последовательности внешних определений. Внешнее определение описывает идентификатор как имеющий класс памяти static и определяет его тип. Спецификатор типа (#8.2) может также быть пустым, и в этом случае принимается тип int. Область видимости внешних определений простирается до конца файла, в котором они описаны, так же, как действие описаний сохраняется до конца блока. Синтаксис внешних определений тот же, что и у описаний, за исключением того, что только на этом уровне и внутри описаний классов может быть задан код (текст программы) функции.
Определения функций имеют вид
определение_функции: спецификаторы_описания описатель_функции opt инициализатор_базового_класса opt тело_функции
описатель_функции: описатель ( список_описаний_параметров )
тело_функции: составной_оператор
int max (int a,int b,int c) { int m = (a > b) ? a : b; return (m > c) ? m : c; }
инициализатор_базового_класса: : ( список_параметров opt )
struct base { base (int); ... }; struct derived : base { derived (int); ... }; derived.derived (int a) : (a+1) { ... } derived d (10);
Определения внешних данных имеют вид
определение_данных: описание
См. #4.1.
Компилятор языка C++ содержит препроцессор, способный выполнять
макроподстановки, условную компиляцию и включение именованных
файлов. Строки, начинающиеся с #, относятся к препроцессору. Эти
строки имеют независимый от остального языка синтаксис; они могут
появляться в любом месте оказывать влияние, которое
распространяется (независимо от области видимости) до конца
исходного файла программы.
Заметьте, что определения const и inline дают альтернативы для
большинства использований #define.
Командная строка компилятора имеет вид
#define идент строка_символов
#define идент( идент , ..., идент ) строка_символов
#undef идент
Командная строка компилятора вида
#include "имя_файла"
#include <имя_файла>
Командная строка компилятора вида
#if выражение
#ifdef идент
#ifndef идент
#else
#endif
Для помощи другим препроцессорам, генерирующим программы на C, строка вида
#line константа "имя_файла"
См. #8.1.
В этом разделе кратко собрано описание действий, которые могут совершаться над объектами различных типов.
Классовые объекты могут присваиваться, передаваться функциям как параметры и возвращаться функциями. Другие возможные операции, как, например, проверка равенства, могут быть определены пользователем; см. #8.5.10.
Есть только две вещи, которые можно проделывать с функцией: вызывать ее и брать ее адрес. Если в выражении имя функции возникает не в положении имени функции в вызове, то генерируется указатель на функцию. Так, для передачи одной функции другой можно написать
typedef int (*PF) (); extern g (PF); extern f (); ... g (f);
g (PF funcp) { ... (*funcp) (); ... }
Всякий раз, когда в выражении появляется идентификатор типа
массива, он преобразуется в указатель на первый член массива. Из-за
преобразований массивы не являются адресами. По определению
операция индексирования [] интерпретируется таким образом, что
E1[E2] идентично *((E1)+(E2)). В силу правил преобразования,
применяемых к +, если E1 массив и E2 целое, то E1[E2] относится к
E2-ому члену E1. Поэтому, несмотря на такое проявление асимметрии,
индексирование является коммутативной операцией.
Это правило сообразным образом применяется в случае многомерного
массива. Если E является n-мерным массивом ранга i*j*...*k, то
возникающее в выражении E преобразуется в указатель на (n-1)-мерный
массив ранга j*...*k. Если к этому указателю, явно или неявно, как
результат индексирования, применяется операция *, ее результатом
является (n-1)-мерный массив, на который указывалось, который сам
тут же преобразуется в указатель.
Рассмотрим, например,
int x[3][5];
Определенные преобразования, включающие массивы, выполняются, но
имеют зависящие от реализации аспекты. Все они задаются с помощью
явной операции преобразования типов, см. ##7.2 и 8.7.
Указатель может быть преобразован к любому из целых типов,
достаточно больших для его хранения. То, какой из int и long
требуется, является машинно зависимым. Преобразующая функция также
является машинно зависимой, но предполагается, что она не содержит
сюрпризов для того, кто знает структуру адресации в машине.
Подробности для некоторых конкретных машин были даны в #2.6.
Объект целого типа может быть явно преобразован в указатель.
Преобразующая функция всегда превращает целое, полученное из
указателя, обратно в тот же указатель, но в остальных случаях
является машинно зависимой.
Указатель на один тип может быть преобразован в указатель на
другой тип. Использование результирующего указателя может вызывать
особые ситуации, если исходный указатель не указывает на объект,
соответствующим образом выравненный в памяти. Гарантируется, что
указатель на объект данного размера может быть преобразован в
указатель на объект меньшего размера и обратно без изменений.
Например, программа, выделяющая память, может получать размер (в
байтах) размещаемого объекта и возвращать указатель на char; это
можно использовать следующим образом.
extern void* alloc (); double* dp; dp = (double*) alloc (sizeof (double)); *dp= 22.0 / 7.0;
В нескольких местах C++ требует выражения, вычисление которых дает константу: в качестве границы массива (#8.3), в case выражениях (#9.7), в качестве значений параметров функции, присваиваемых по умолчанию, (#8.3), и в инициализаторах (#8.6). В первом случае выражение может включать только целые константы, символьные константы, константы, описанные как имена, и sizeof выражения, возможно, связанные бинарными операциями
+ - * / % & | ^ << >> == != < > <= >= && ||
- ~ !
? :
Определенные части C++ являются машинно зависимыми по своей сути.
Следующий ниже список мест возможных затруднений не претендует на
полноту, но может указать на основные из них.
Как показала практика, характеристики аппаратуры в чистом виде,
такие, как размер слова, свойства плавающей арифметики и целого
деления, не создают особых проблем. Другие аппаратные аспекты
отражаются на различных программных разработках. Некоторые из них,
особенно знаковое расширение (преобразование отрицательного символа
в отрицательное целое) и порядок расположения байтов в слове,
являются досадными помехами, за которыми надо тщательно следить.
Большинство других являются всего лишь мелкими сложностями.
Число регистровых переменных, которые фактически могут быть
помещены в регистры, различается от машины к машине, как и
множество фактических типов. Тем не менее, все компиляторы на
"своей" машине все делают правильно; избыточные или недействующие
описания register игнорируются.
Некоторые сложности возникают при использовании двусмысленной
манеры программирования. Писать программы, зависящие от какой-либо
из этих особенностей, районе неблагоразумно.
В языке не определен порядок вычисления параметров функции. На
некоторых машинах он слева направо, а на некоторых справа налево.
Порядок появления некоторых побочных эффектов также
недетерминирован.
Поскольку символьные константы в действительности являются
объектами типа int, то могут быть допустимы многосимвольные
константы. Однако конкретная реализация очень сильно зависит от
машины, поскольку порядок, в котором символы присваиваются слову,
различается от машины к машине. На некоторых машинах поля в слове
присваиваются слева направо, на других справа налево.
Эти различия невидны для отдельных программ, не позволяющих себе
каламбуров с типами (например, преобразования int указателя в char
указатель и просмотр памяти, на которую указывает указатель), но
должны приниматься во внимание при согласовании внешне предписанных
форматов памяти.
Операция new (#7.2) вызывает функцию
extern void* _new (long);
extern void _delete (void*);
class cl { int v[10]; cl () { this = my_own_allocator (sizeof (cl)); } ~cl () { my_own_deallocator (this); this = 0; } }
Мы надеемся, что эта краткая сводка синтаксиса C++ поможет пониманию. Она не является точным изложением языка.
выражение: терм выражение бинарная_операция выражение выражение ? выражение : выражение список_выражений терм: первичный * терм & терм - терм ! терм ~ терм ++терм --терм терм++ терм-- ( имя_типа) выражение имя_простого_типа ( список_выражений) sizeof выражение sizeof ( имя_типа ) new имя_типа new ( имя_типа ) первичный: id :: идентификатор константа строка this ( выражение ) первичный[ выражение ] первичный ( список_выражений opt ) первичный.id первичный->id id: идентификатор typedef-имя :: идентификатор список_выражений: выражение список_выражений, выражение операция: унарная_операция бинарная_операция специальная_операция Бинарные операции имеют приоритет, убывающий в указанном порядке: бинарная_операция: * / % + - << >> < > == != & ^ | && || = += -= *= /= %= ^= &= |= >>= <<= унарная_операция: * & - ~ ! ++ -- специальная_операция: () [] имя_типа: спецификаторы_описания абстрактный_описатель абстрактный_описатель: пустой * абстрактный_описатель абстрактный_описатель ( список_описаний_параметров ) абстрактный_описатель [ константное_выражение opt ] ( абстрактный_описатель ) простое_имя_типа: typedef-имя char short int long unsigned float double typedef-имя: идентификатор
описание: спецификаторы_описания opt список_описателей opt ; описание_имени asm-описание описание_имени: агрег идентификатор ; enum идентификатор ; агрег: class struct union asm-описание: asm ( строка ); спецификаторы_описания: спецификатор_описания спецификатор_описания opt спецификатор_описания: имя_простого_типа спецификатор_класса enum_спецификатор sc_спецификатор фнк_спецификатор typedef friend const void sc_спецификатор: auto extern register static фнк-спецификатор: inline overload virtual список_описателей: иниц-описатель иниц-описатель , список_описателей иниц-описатель: описатель инициализатор opt описатель: оп_имя ( описатель ) * const opt описатель & const opt описатель описатель ( список_описаний_параметров ) описатель [ константное_выражение opt ] оп_имя: простое_оп_имя typedef-имя . простое_оп_имя простое_оп_имя: идентификатор typedef-имя - typedef-имя имя_функции_операции имя_функции_операции: операция операция список_описаний_параметров: список_описаний_прм opt ... opt список_описаний_прм : список_описаний_прм , описание_параметра описание_параметра описание_параметра: спецификаторы_описания описатель спецификаторы_описания описатель = константное_выражение спецификатор_класса: заголовок_класса {список_членов opt } заголовок_класса {список_членов opt public : список_членов opt } заголовок_класса : агрег идентификатор opt агрег идентификатор opt : public opt typedef-имя список_членов : описание_члена список_членов opt описание_члена: спецификаторы_описания opt описатель_члена ; описатель_члена: описатель идентификатор opt : константное_выражение инициализатор: = выражение = { список_инициализаторов} = { список_инициализаторов, } (список_выражений ) список_инициализаторов : выражение список_инициализаторов , список_инициализаторов { список_инициализаторов } enum-спецификатор: enum идентификатор opt { enum-список } enum-список: перечислитель enum-список , перечислитель перечислитель: идентификатор идентификатор = константное_выражение
составной_оператор: { список_описаний opt список_операторов opt } список_описаний: описание описание список_описаний список_операторов: оператор оператор список_операторов оператор: выражение ; if ( выражение ) оператор if ( выражение ) оператор else оператор while ( выражение ) оператор do оператор while ( выражение ) ; for ( выражение opt ; выражение opt ; выражение opt ) оператор switch ( выражение ) оператор case константное выражение : оператор default : оператор break; continue; return выражение opt ; goto идентификатор ; идентификатор : оператор delete выражение ; asm ( строка ) ; ;
программа: внешнее_определение внешнее_определение программа внешнее_определение: определение_функции описание определение_функции: спецификаторы_описания opt описатель_функции инициализатор_базового_класса opt тело_функции описатель_функции: описатель ( список_описаний_параметров) тело_функции: составной_оператор инициализатор_базового_класса: : ( список_параметров opt )
#define идент строка_символов #define идент( идент,...,идент ) строка символов #else #endif #if выражение #ifdef идент #ifndef идент #include "имя_файла" #include <имя_файла> #line константа "имя_файла" #undef идент
Типы параметров функции могут быть заданы (#8.4) и будут проверяться (#7.1). Могут выполняться преобразования типов.
Для выражений с числами с плавающей точкой может использоваться
плавающая арифметика одинарной точности; #6.2.
Имена функций могут быть перегружены; #8.6
Операции могут быть перегружены; #7.16, #8.5.10.
Может осуществляться inline-подстановка функций; #8.1.
Объекты данных могут быть константными (const); #8.3.
Могут быть описаны объекты ссылочного типа; #8.3, #8.6.3
Операции new и delete обеспечивают свободное хранение в памяти;
#17.
Класс может обеспечивать скрытые данные (#8.5.8), гарантированную инициализацию (#8.6.2), определяемые пользователем преобразования (#8.5.6), и динамическое задание типов через использование виртуальных функций (#8.5.4).
Имя класса является именем типа; #8.5.
Любой указатель может присваиваться [указателю] void* без
приведения типов; #7.14.
Понятие же "физического вакуума" в релятивистской квантовой теории поля подразумевает, что во-первых, он не имеет физической природы, в нем лишь виртуальные частицы у которых нет физической системы отсчета, это "фантомы", во-вторых, "физический вакуум" - это наинизшее состояние поля, "нуль-точка", что противоречит реальным фактам, так как, на самом деле, вся энергия материи содержится в эфире и нет иной энергии и иного носителя полей и вещества кроме самого эфира.
В отличие от лукавого понятия "физический вакуум", как бы совместимого с релятивизмом, понятие "эфир" подразумевает наличие базового уровня всей физической материи, имеющего как собственную систему отсчета (обнаруживаемую экспериментально, например, через фоновое космичекое излучение, - тепловое излучение самого эфира), так и являющимся носителем 100% энергии вселенной, а не "нуль-точкой" или "остаточными", "нулевыми колебаниями пространства". Подробнее читайте в FAQ по эфирной физике.