сылка при объявлении всегда должна быть проинициализирована!

int a,b;
int &alt=a; // alt — другое имя переменной а (ссылка на a)
alt = b; // a=b;
alt++; // a++;

Если объявлен указатель

int *ptr = &a;

то истины следующие выражения:

*ptr == alt; // истина, сравниваются значения
ptr == &alt; // истина, сравниваются адреса

Ссылку можно рассматривать как постоянный указатель, который всегда разыменован, для него не надо выполнять операцию косвенной адресации *.

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

Возможно инициализировать ссылка на константу:

const char &new_line='\n';

В этом случае компилятор создает некоторую временную переменную temp и ссылку на нее:

char temp = '\n';
const char &new_line = temp;

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

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

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

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

· во-первых, в функции для данного параметра надо выполнять операцию разыменования,

· во-вторых, при вызове функции надо передавать не саму переменную, а ее адрес.

Пример. Функция, меняющая местами два целых числа:

Без использования ссылок С использованием ссылок
void swap (int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void swap (int &a, int &b) { int temp = a; a = b; b = temp; }
Вызов: int x = 10; int y = 5; swap(&x, &y); Вызов: int x = 10; int y = 5; swap(x, y);

При использовании ссылок в качестве параметров, наряду с указанными преимуществами есть два существенных недостатка:

· Фактический аргумент, переданный в функцию по ссылке, может быть изменен функцией без ведома вызывающей программы. Чтобы этого избежать, параметры, которые не должны изменяться, должны определяться с ключевым словом const. При попытке изменить параметр, объявленный как const будет сообщение об ошибке.

· Если при вызове функции происходит несоответствие типов фактических и формальных параметров, С++ выполняет преобразование типа, но для ссылок преобразование типа выполняется через создание промежуточной переменной.

void swap (int &, int &);
int main() {
int x=10;
unsigned int y;
y=5;
swap(x, y);
...
}

Компилятор будет выполнять следующие преобразования:

int temp = (int)y;
int &t = temp;
swap(x, t);

В результате swap() поменяет местами значения x и temp. После выхода из функции переменная temp удалится, а y останется неизменной.

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

· если возвращаемое значение — указатель, то нельзя оператором return; возвращать адрес локальной переменной.

· если возвращаемое значение — ссылка, то нельзя оператором return возвращать локальную переменную. (Так как после выхода из функции переменная не существует, и мы получим повисшую ссылку).

Чаще всего потребность в ссылках возникает при перегрузке операций.

 

Билет 5

Вопрос 1 :Операция языка C.Примеры.

Над объектами в языке Си могут выполняться различные операции:

· операции присваивания;

· операции отношения;

· арифметические;

· логические;

· cдвиговые операции.

Результатом выполнения операции является число.

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

Операция присваивания

Операция присваивания обозначается символом = и выполняется в 2 этапа:

· вычисляется выражение в правой части;

· результат присваивается операнду, стоящему в левой части:

объект = выражение;

Пример:

int a = 4; // переменной a присваивается значение 4
int b;
b = a + 2; // переменной b присваивается значение 6,

// вычисленное в правой части

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

объект = (тип)выражение;

float a = 241.5;

// Перед вычислением остатка от деления a приводится к целому типу
int b = (int)a % 2; // b = 1

Операции отношения

Основные операции отношения:

· == эквивалентно — проверка на равенство;

· != не равно — проверка на неравенство;

· < меньше;

· > больше;

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

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

Операции отношения используются при организации условий и ветвлений. Результатом этих операций является 1 бит, значение которого равно 1, если результат выполнения операции - истина, и равно 0, если результат выполнения операции - ложь.

Арифметические операции

Основные бинарные операции, расположенные в порядке уменьшения приоритета:

· умножение *;

· деление /;

· сложение +;

· вычитание -;

· остаток от целочисленного деления %.

Основные унарные операции:

· инкрементирование (увеличение на 1) ++;

· декрементирование (уменьшение на 1) --;

· изменение знака -.

Результат вычисления выражения, содержащего операции инкрементирования или декрементирования, зависит от того, где расположен знак операции (до объекта или после него). Если
операция расположена до объекта, то сначала происходит изменение значения переменной на 1, а потом это значение используется для выполнения следующих операций. Если операция ++ или -- расположена после переменной, то сначала выполняется операция, а потом значение переменной изменяется на 1.
Пример:

int a=2; int b=3; int c; c = a*++b; // c=8, поскольку в операции умножения уже b=4 int a=2; int b=3; int d; d = a*b++; // d=6, поскольку в операции умножения b=3, следующим действием будет b=4

Бинарные арифметические операции могут быть объединены с операцией присваивания:

· объект *= выражение; // объект = объект * выражение

· объект /= выражение; // объект = объект / выражение

· объект += выражение; // объект = объект + выражение

· объект -= выражение; // объект = объект - выражение

· объект %= выражение; // объект = объект % выражение

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

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

· условные;

· побитовые.

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

· 1 если выражение истинно;

· 0 если выражение ложно.

Вообще, все значения, отличные от нуля, интерпретируются условными логическими операциями как истинные.

Основные условные логические операции:

· && - И (бинарная) — требуется одновременное выполнение всех операций отношения;

· || - ИЛИ (бинарная) — требуется выполнение хотя бы одной операции отношения;

· ! - НЕ (унарная) — требуется невыполнение операции отношения.

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

Основные побитовые логические операции в языке Си:

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

· | дизъюнкция (логическое ИЛИ) - бинарная операция, результат которой равен 1 когда хотя бы один из операндов равен 1;

· ~ инверсия (логическое НЕ) - унарная операция, результат которой равен 0 если операнд единичный, и равен 1, если операнд нулевой;

· ^ исключающее ИЛИ - бинарная операция, результат которой равен 1, если только один из двух операндов равен 1 (в общем случае если во входном наборе операндов нечетное число единиц).

Для каждого бита результат выполнения операции будет получен в соответствии с таблицей.

a b a & b a | b ~a a ^ b

Пример:

unsigned char a = 14; // a = 0000 1110
unsigned char b = 9; // b = 0000 1001
unsigned char c, d, e, f;
c = a & b; // c = 8 = 0000 1000
d = a | b; // d = 15 = 0000 1111
e = ~a; // e = 241 = 1111 0001
f = a ^ b; // f = 7 = 0000 0111


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

Бит Маска
0x01
0x02
0x04
0x08
0x10
0x20
0x40
0x80

Для установки определенного бита необходимо соответствующий бит маски установить в 1 и произвести операцию побитового логического ИЛИ с константой, представляющей собой маску:

unsigned char a = 3;
a = a | 0x04; // a = 7, бит 2 установлен

Для сброса определенного бита необходимо соответствующий бит маски сбросить в 0 и произвести операцию побитового логического И с константой, представляющей собой инверсную маску:

unsigned char a = 3;
a = a & (~0x02); // a = 1, бит 1 сброшен

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

· объект &= выражение; // объект = объект & выражение

· объект |= выражение; // объект = объект | выражение

· объект ^= выражение; // объект = объект ^ выражение

Сдвиговые операции

Операции арифметического сдвига применяются в целочисленной арифметике и обозначаются как:

· >> - сдвиг вправо;

· << - сдвиг влево.

Общий синтаксис осуществления операции сдвига:
объект = выражение сдвиг КоличествоРазрядов;
Пример:

unsigned char a=6; // a = 0000 0110
unsigned char b;
b = a >> 1; // b = 0000 0110 >> 1 = 0000 0011 = 3

Арифметический сдвиг целого числа вправо >> на 1 разряд соответствует делению числа на 2.
Арифметический сдвиг целого числа влево << на 1 разряд соответствует умножению числа на 2.

 

Вопрос 2:Базовые принципы ООП

Объектно-ориентированное программирование основано на «трех китах» - трех важнейших принципах, придающих объектам новые свойства. Этими принципами являются инкапсуляция, наследование и полиморфизм.

Инкапсуляция

Инкапсуляция есть объединение в единое целое данных и алгоритмов обработки этих данных. В рамках ООП данные называются полями объекта, а алгоритмы - объектными методами.

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

Другим немаловажным следствием инкапсуляции является легкость обмена объектами, переноса их из одной программы в другую. Можно сказать, что ООП «провоцирует» разработку библиотек объектов, таких как Turbo Vision.

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

Наследование есть свойство объектов порождать своих потомков. Объект-потомок автоматически наследует от родителя все поля и методы, может дополнять объекты новыми полями и заменять (перекрывать) методы родителя или дополнять их.

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

Последовательное проведение в жизнь принципа «наследуй и изменяй» хорошо согласуется с поэтапным подходом к разработке крупных программных проектов и во многом стимулирует такой подход.

Полиморфизм

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

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