Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Учебник Информатика.doc
Скачиваний:
121
Добавлен:
28.08.2019
Размер:
4.53 Mб
Скачать

4.13. Классификации языков программирования и примеры языков

В разделе 4.6 приводятся классификации языков программирования. В качестве примеров рассматриваются, в частности, языки С++ 33 и LISP 34. Ниже приводятся описания этих языков.

4.13.1. Лексические основы языка С++

Алфавит языка С++

  • прописные и строчные буквы латинского алфавита

  • цифры: 0 1 2 3 4 5 6 7 8 9

  • специальные знаки: “ ‘ . , ; : ? ! {} [] () < = > + - * / % \ | _ & # ~ ^

  • пробельные символы: пробел, табуляция, конец строки.

Лексемы языка С++

  • идентификаторы;

  • ключевые (служебные) слова;

  • константы;

  • знаки операций;

  • разделители (знаки пунктуации).

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

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

Константа – это лексема, представляющая изображение фиксированного числового (целого или вещественного), символьного или строкового значения.

Знак операции – это лексема, обеспечивающая формирование и последующее вычисление выражений. В зависимости от контекста один и тот же знак может обозначать разные операции.

Разделитель (знак пунктуации) – это элемент, обеспечивающий отделение друг от друга прочих лексем языка С++.

Константы языка С++

Целые константы:

  • десятичные (последовательность цифр, начинающихся не с нуля), например: 5 123 95645;

  • восьмеричные (начинаются с нуля и состоят из цифр 0, 1, 2, 3, 4, 5, 6, 7), например: 05 0123 015645;

  • шестнадцатеричные (начинаются с 0х и состоят из цифр и букв a(A), b(B), c(C), d(D), e(E), f(F)), например: 0х5F 0х123 0хе56а.

Вещественные константы

Состоят из целой части, десятичной точки, дробной части, признака степени e (или E), значения степени (возможно со знаком). Распознаются по внешним признакам: наличию десятичной точки и (или) признака степени, например: 66. .12 3.14 1.12е-2 2Е+6.

Символьные (литерные) константы

Представляют собой символ, заключенный в апострофы. Значением символьной константы является числовое значение её внутреннего кода. Вместо символа может использоваться комбинация символов, начинающаяся с символа обратной косой черты (\). Такая комбинация применяется для использования элементов кодировочной таблицы, не имеющих графического изображения, для использования символов апостроф (‘), обратная косая черта (\), знак вопроса (?) и кавычки (“). Кроме того, обратная косая черта позволяет вводить символьные константы, явно задавая их коды в восьмеричном или шестнадцатеричном виде.

Примеры: ‘z’ ‘*’ ‘\n’ ‘\012’ ‘\x07’

Строковые константы (строки)

Представляют собой последовательность символов, заключенных в кавычки, например: “\nHello!”. Строка имеет вид символьного (типа char) массива. Размер строки в байтах равен количеству символов плюс один байт, в который помещается символ конца строки ‘\0’.

Знаки операций

Унарные операции

& операция получения адреса операнда;

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

- унарный минус – изменяет знак операнда;

~ поразрядное инвертирование двоичного кода целочисленного аргумента (побитовое отрицание);

! логическое отрицание значения операнда (отрицание любого ненулевого числа (!2 !(-5) !1) равно нулю, а отрицание нуля (!0) равно единице;

++ увеличение на единицу (инкремент); операндом может быть только леводопустимое выражение (например, переменная), ошибкой является использование в качестве операнда константы или произвольного выражения (++5 (j+k)++); есть два варианта использования операции: префиксная операция (++i) – увеличение операнда до его использования, постфиксная операция (i++) – увеличение операнда после его использования;

-- уменьшение на единицу (декремент);

sizeof – вычисление размера памяти (в байтах), отведенной для размещения операнда; разрешены два формата записи: sizeof унарное_выражение и sizeof(тип).

Бинарные операции

  1. Аддитивные:

+ бинарный плюс (сложение арифметических операндов или сложение указателя с целочисленным операндом);

- бинарный минус (тоже, только вычитание).

  1. Мультипликативные:

* умножение операндов арифметического типа;

/ деление операндов арифметического типа; при целочисленных операндах абсолютное значение результата округляется до целого (например, 20/3 равно 6);

% получение остатка от деления целочисленных операндов ( 13%4 равно 1).

  1. Операции отношения (сравнения):

< меньше, чем;

> больше, чем;

<= меньше или равно;

>= больше или равно;

== равно;

!= не равно.

  1. Логические операции:

&& конъюнкция (И) арифметических операндов и отношений; целочисленный результат: 0 (ложь) или 1 (истина);

|| дизъюнкция (ИЛИ) арифметических операндов и отношений; целочисленный результат: 0 (ложь) или 1 (истина).

  1. Операции присваивания:

= присвоить значение выражения-операнда из правой части левому операнду (например, y=2*x+5);

*= присвоить левому операнду произведение значений обоих операндов (например, x*=2 эквивалентно x=x*2).

Аналогично выглядит сочетание присваивания с другими операциями:

/=, %=, +=, -=, <<=, >>=, &=, |=, ^= .

Очередность выполнения операций

Очередность выполнения операций определяется:

  1. Рангом операций (их приоритетом). В первую очередь выполняются операции 1-го ранга.

  2. Правилом ассоциативности, если в выражении несколько операций одного ранга. Операции, помеченные в таблице 1 знаком , выполняются слева направо, помеченные знаком  – справа налево.

Таблица 4.1.

Приоритеты операций

Ранг

Операции

Правило ассоциативности

1

() [] -> ::

2

! ’ ~ - ++ --& * (тип) тип() sizeof new delete

3

* ->*

4

* / % (мультипликативные бинарные)

5

+ - (аддитивные бинарные)

6

<< >>

7

< <= >= >

8

== !=

9

&

10

^

11

|

12

&&

13

||

14

?:

15

= *= /= %= += -= &= ^= |= <<= >>=

16

,(операция запятая)

Комментарии

Используются для выполнения пометок в тексте программы и для временного выключения ненужных блоков программы. Комментарии выделяются в тексте программы двумя способами:

  1. комментарием считается всё, что стоит правее двух наклонных черт // до конца строки;

  2. комментарием считается всё, что ограничено знаками: /* слева и */ справа.

Основные типы данных языка С++

Тип данных определяет:

  • внутреннее представление данных в памяти компьютера;

  • множество значений, которые могут принимать величины этого типа;

  • операции и функции, которые можно использовать с величинами этого типа.

Все типы языка С++ можно разделить на основные и производные (составные). В языке С++ определён ряд основных типов данных для представления целых, вещественных, символьных и логических величин.

Целые типы

Размер основного целого типа int зависит от разрядности процессора. Для 32-разрядного – 4 байта. Спецификатор short перед int указывает компилятору, что под целую величину следует выделить 2 байта независимо от разрядности процессора. По умолчанию во всех целочисленных типах старший бит используется как знаковый (0 – положительное число, 1 – отрицательное число), при использовании спецификатора unsigned старший разряд используется как часть кода числа и тип можно использовать для представления только положительных чисел.

Вещественные типы

Стандарт языка С++ определяет три типа данных для хранения чисел с плавающей точкой: float, double, long double. Величины типа float требуют для хранения 4 байта, величины типа double требуют 8 байт, величины типа long double – 10 байт.

Символьный тип

Под величины символьного типа char отводится 1 байт. Этого достаточно для хранения кода любого символа из 256-символьного набора ASCII. Тип char может также использоваться для хранения целых чисел.

Описание переменных

Переменная – это именованная область памяти, в которой хранятся данные определённого типа. Имя переменной – это идентификатор, который должен быть описан прежде, чем будет использоваться в программе. При описании идентификатор связывается с типом, например: char c;. Часто описания одновременно являются определениями, задающими значение переменной, например: int k = 1;

Использование в описании модификатора const позволяет создавать именованные константы, например: const double pi = 3.14159;

Инициализация именованной константы обязательна.

Базовые конструкции языка С++

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

Выражение состоит из операндов, знаков операций и скобок и используется для вычисления некоторого значения определённого типа. Каждый операнд является выражением или его частным случаем – константой или переменной.

Любое выражение, завершающееся точкой с запятой, рассматривается как оператор, выполнение которого заключается в вычислении выражения, например:

i++; a*=b+c;

x=(-b+sqrt(d))/(2*a);

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

Используется для разветвления процесса вычислений на два направления. Формат оператора:

if(выражение)оператор1; else оператор2;

Сначала вычисляется выражение. Если оно не равно нулю, выполняется первый оператор, иначе – второй. Второй оператор вместе со словом else может отсутствовать. Если в какой-либо ветви требуется выполнить несколько операторов, их объединяют в блок, заключая в фигурные скобки. Примеры:

if(a>0){b=1;c=2;}

if(a++)b++;

if(b>a)max=b;else max=a;

Переключатель switch

Оператор switch (переключатель) предназначен для разветвления процесса вычислений на несколько направлений. Формат оператора:

switch(выражение){case константа1:[список_операторов1]

case константа2:[список_операторов2]

...

case константаN:[список_операторовN]

default: список_операторов}

Вычисление оператора switch начинается с вычисления значения выражения. Оно должно быть целочисленным. Управление передаётся тому списку операторов, который следует за константой, совпавшей с вычисленным значением. Далее последовательно вычисляются все нижерасположенные операторы. Если ни одна константа не совпала со значением выражения, вычисляются операторы стоящие после слова default.

Цикл с предусловием while

Тело цикла (оператор или блок операторов) выполняется до тех пор пока верно условие. Формат оператора:

while(выражение)тело_цикла

Выражение определяет условие повторения тела цикла. Для выполнения тела цикла оно должно быть истинным, то есть не равно нулю. Пример вычисления факториала числа:

int f=1;

while(x>1)

{f*=x; x--;}

Цикл с постусловием do while

Формат оператора:

do тело_цикла while(выражение);

Пример вычисления квадратного корня числа x с заданной точностью ε:

y=1;

do{y0=y;

y=(y0+x/y0)/2;

}while(fabs(y-y0)>=eps);

Цикл с параметром for

Цикл с параметром for имеет следующий формат:

for(инициализация; выражение; модификация) тело_цикла

Инициализация используется для присвоения начальных значений переменным, используемым в цикле. Она выполняется один раз в начале цикла. В инициализации можно расположить несколько операторов, разделенных запятой. Выражение определяет условие выполнения цикла и вычисляется в начале каждой итерации. Модификация выполняется в конце каждой итерации и содержит один или несколько операторов, разделенных запятой, изменяющих значения используемых переменных. Любая часть оператора for может быть опущена, но точки с запятой остаются как обязательный элемент конструкции. Пример вычисления суммы чисел от 1 до 100:

for(int i=1,s=0;i<=100;i++)s+=i;

Производные типы данных языка С++

Из описанных выше основных типов с помощью операций *, &, [], () и механизмов определения типов структурированных данных можно конструировать множество производных типов.

Перечисления enum

Перечисления служат для определения совокупности целых именованных констант. По существу это обычные целые константы типа int, которым приписаны уникальные и удобные для использования имена.

Формат описания перечисления:

num имя_типа{список_констант};

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

Например, в перечислении enum{zero,one,two}; определены три именованные константы со значениями 0, 1 и 2.

Указатели

Указатели предназначены для хранения адресов памяти. Указатель всегда связан с каким-либо конкретным типом. Простейшее описание указателя на объект имеет вид:

тип *указатель=адрес;

Инициализация указателя может быть произведена:

  • с помощью операции получения адреса: int *p=&a;

  • с помощью значения другого указателя: int *p2=p;

  • путем указания адреса в явном виде: int *p3=(int*)0xB8000000;

  • путем выделения участка динамической памяти: int *p4=new int;

Выделенная память освобождается при завершении программы или с помощью операции освобождения динамической памяти: delete p4;

С указателями можно выполнять операции: обращение по адресу, присваивание, сложение с константой, вычитание, инкремент, декремент, сравнение, приведение типа. Примеры:

*p=5; p2=p+2; int a=p2-p; p++;

Ссылки

Формат описания ссылки: тип &ссылка=объект;

Ссылка представляет собой синоним имени объекта, указанного при инициализации. Пример: int k; int &kol=k;

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

Массивы

Массив – это именованная совокупность однотипных данных. Формат описания массива:

тип имя[размерность]={список_инициализаторов};

Имя – это указатель на начальный адрес размещения массива. Размерность определяет количество элементов массива. Она должна быть задана константой. Элементам массива, начиная с нулевого (начального) элемента, последовательно присваиваются инициализирующие значения. Их количество не должно превышать размерность массива. Инициализация массива может быть опущена. Примеры:

int m[10];

float massiv[5]={1,2,3};

Чтобы создать массив с количеством элементов, задаваемым переменной, используется операция динамического выделения памяти:

int n=5; float *m=new float[n];

Указатель m становится именем динамического массива. Освобождение памяти в этом случае происходит следующим образом: delete[]m;

Для доступа к элементу массива после имени указывается его номер в квадратных скобках: m[5]=1;

Структуры

Структура – это производный тип, объединяющий данные разного типа. Форма записи:

struct имя_типа{

тип1 элемент1;

тип2 элемент2;

...

типN элементN;

} имя_объекта={ список_инициализаторов };

Элементы структуры называют полями структуры; они могут иметь любой тип, кроме типа этой же структуры. В описании может быть опущено имя типа или имя объекта, но не оба сразу. Инициализация указывается при необходимости. Пример:

struct student{

char name[20];

int age;

}a={“Иванов”,18};

Для переменных структурного типа определена операция присваивания, при этом происходит поэлементное копирование:

student b; b=a;

Доступ к полям структуры выполняется с помощью операций прямого обращения через имя объекта и косвенного обращения через указатель на объект. Примеры:

student x; x.age=20;

student *px=&x; px->age=20;

Функции

Функция – это именованная последовательность описаний и операторов, выполняющих законченное действие. Любая программа на С++ состоит из функций, одна из которых носит имя main. С неё начинается выполнение программы.

Объявление и определение функции

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

тип имя(список_параметров);

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

int fact(int x)

{int f=1;

while(x>1){f*=x; x--;}

return f;

}

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

Возвращаемое значение

Механизм возврата из функции в вызвавшую её функцию реализуется оператором:

return выражение;

Функция может содержать несколько операторов return (это определяется потребностями алгоритма). Если функция описана как void, выражение не указывается. Оператор return можно опускать для функции типа void и для функции main.

Параметры функции

Существует два способа передачи параметров в функцию: по значению и по адресу.

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

При передаче по адресу в стек заносятся копии адресов аргументов, а функция осуществляет доступ к ячейкам памяти по этим адресам и может изменить исходные значения аргументов.

void f(int a, int *b, int &c)

{a++; (*b)++; c++;}

...

int x=1; int y=1; int z=1;

f(x,&y,z);

В данном примере функция изменит значения переданных по адресу переменных y и z.

Если требуется запретить изменение параметра внутри функции, используется модификатор const, например: void f(сonst int a);

Параметры со значениями по умолчанию

Чтобы упростить вызов функции, в её заголовке можно указать значения параметров по умолчанию. Эти параметры должны быть последними в списке и могут опускаться при вызове функции. В качестве значений параметров по умолчанию могут использоваться константы, глобальные переменные и выражения. Пример:

int f(int a, int b=1){return a+b;}

Варианты вызова данной функции:

int x=f(5); x=f(3,4);

Классы

Идея классов является основой объектно-ориентированного программирования (ООП). В языке С++ основные принципы ООП реализованы эффективно, красиво и непротиворечиво, что и явилось основой успешного распространения этого языка и внедрения подобных средств в другие языки программирования.

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

Описание класса

Класс является абстрактным типом данных, определяемым пользователем, и представляет собой модель реального объекта в виде данных и функций для работы с ними. Данные класса называются полями, а функции класса – методами. Поля и методы называются элементами класса. Формат описания класса:

class имя{private: описание_скрытых_элементов

public: описание_доступных_элементов};

Спецификаторы доступа private и public управляют видимостью элементов класса. Элементы, описанные после private, видимы только внутри класса. Этот вид доступа принят в классе по умолчанию. Интерфейс класса описывается после спецификатора public.

Поля класса могут иметь любой тип, кроме типа этого же класса (но могут быть указателями или ссылками на этот класс). Инициализация полей при описании не допускается.

В примере представлен класс, описывающий человека:

class man

{private:

char name[20];

int age;

public:

man(char*na=0, int ag=0);

void print();

};

Описание объектов

Конкретные переменные типа «класс» называются экземплярами класса, или объектами. При создании каждого объекта выделяется память, достаточная для хранения всех полей, и автоматически вызывается конструктор, выполняющий их инициализацию. При выходе объекта из области действия он уничтожается, при этом автоматически вызывается деструктор. Примеры описания объектов класса man:

man A; man B(“Иванов”); man C(“Петров”,20);

Доступ к элементам объекта аналогичен доступу к полям структуры:

man A; A.print();

man *pA=new man; pA->print();

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

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

Параметры конструктора могут иметь любой тип, кроме этого же класса. Можно задавать значения параметров по умолчанию. Их может содержать только один из конструкторов.

Если программист не указал ни одного конструктора, компилятор создаёт его автоматически. Конструкторы не наследуются.

Пример реализации конструктора объявленного в классе man:

man::man(char *na, int ag)

{age=ag;

if(na) strcpy(name,na);

}

Конструктор копирования – это специальный вид конструктора, получающий в качестве единственного параметра указатель на объект этого же класса: T::T(const Т&){тело_конструктора}. Здесь Т – имя класса.

Этот конструктор вызывается при описании нового объекта с инициализацией другим объектом, при передаче объекта в функцию по значению и возврате из функции.

Деструктор – это особый вид метода, применяющийся для освобождения памяти, занимаемой объектом. Имя деструктора начинается с тильды (~), непосредственно за которой следует имя класса. Деструктор не имеет аргументов и возвращаемого значения, не наследуется, может быть виртуальным.

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

Перегрузка операций

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

Функция-операция содержит ключевое слово operator, за которым следует знак переопределяемой операции:

тип operator операция(список_параметров){тело функции}

Пример перегрузки операции присваивания для класса man:

man& man::operator=(man&M)

{if (this==&M) return *this;

age=M.age;

strcpy(name,M.name);

return *this;

}

Ключевое слово this – это константный указатель на вызвавший функцию объект.

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

При описании класса в его заголовке перечисляются все классы, являющиеся для него базовыми. Возможность обращения к элементам этих классов регулируется с помощью ключей доступа private, protected и public. (см. табл.2) Если базовых классов несколько, они перечисляются через запятую.

Рассмотрим наследование классов на примере:

class worker: public man

{protected:

int salary;

public:

worker(char* na=0, int ag=0, int sa=0);

...};

Поля класса man будут унаследованы, если находятся в зоне protected. Конструктор не наследуется и должен быть переопределён. Пример:

worker::worker(char* na, int ag, int sa)

{man::man(na,ag);

salary=sa;}

В теле конструктора размещен вызов конструктора базового класса.

Таблица 4.2

Изменение доступа к элементам класса при наследовании

Ключ доступа

Спецификатор в базовом классе

Доступ в производном классе

private

private

нет

protected

private

public

private

protected

private

нет

protected

protected

public

protected

public

private

нет

protected

protected

public

public