ВВЕДЕНИЕ В ОБЪЕКТНОЕ ПРОГРАММИРОВАНИЕ
Лекция 1. Объектное программирование как технология программирования
-------------------------------------------------------------
Традиционная технология программирования 70-х годов - структурное программирование:
- модульное программирование;
- нисходящее программирование;
- структурное проектирование процедур и данных (программирование без goto).
Язык Паскаль - соответствует указанным принципам и был разработан под влиянием идей структурного программирования.
Альтернативный подход - восходящее программирование - предполагает в простейшем случае создание слоя структур данных и процедур, обеспечивающих полный набор действий над объектами, которые представлены в данной задаче. Пример традиционного подхода библиотека стандартных функций.
Следующий шаг - введение в программу объектов. Под объектом понимается структура данных, которая содержит полную информацию о состоянии соответствующего физического объекта, который отображается программой. В Си этому может соответствовать структура struct), в Паскале - запись (record). Множество объектов одного типа составляют понятие класса. Объектно-ориентированный подход к разработке программ предполагает, что в программе устанавливается взаимно-однозначное соответствие между физическими объектами,
отображаемыми программой, и програмнными объектами, являющимися, по существу, структурированными переменными (в дальнейшем под термином "объект" будем понимать программный объект).
Традиционный подход: ---------- переменная тип данных
Объектно-ориентиро- физический программный класс
ванный подход: объект объект объектов
При создании объектов программист определяет множество функций, при помощи которых (а точнее, исключительно через которые)над объектом выполняется некоторое допустимое множество операций.
Такие функции должны иметь обязательный параметр - ссылку на текущий объект, для которого они вызываются. Сами функции являются неотъемлимой частью понятия класса объектов, так как они определяют возможные действия над объектами одного и того же типа (то есть класса).
Объектно-ориентированные программы можно разрабатывать и с помощью традиционных языков программирования. Рассмотрим пример определения объектов типа "дата" на классическом Си.
//------ структура dat - аналог класса объектов "дата" --------typedef struct dat
{
unsigned day;
unsigned month;
unsigned year;
}
DAT;
//----- набор функций для класса объектов "дата" --------------static int mm[] = {31,28,31,30,31,30,31,31,30,31,30,31};
//----- Проверка на корректность -----------------------------int TestData(p)
DAT *p;
{
if (p->month ==2 && p->day==29 && p->year %4 ==0) return(1);
if (p->month ==0 || p->month >12 ||
p->day ==0 || p->day >mm[p->month])
return(0);
return(1);
}
//------ Следующая дата ----------------------------------------void NextData(p)
DAT *p;
{
p->day++;
if (p->day <= mm[p->month]) return;
if (p->month ==2 && p->day==29 && p->year %4 ==0) return;
p->day=1;
p->month++;
if (p->month !=13) return;
p->month=1;
p->year++;
}
//------- Следующая дата через n дней --------------------------void PlusData(p,n)
DAT *p;
int n;
{
while (n-- !=0) NextData(p);
}
//------- Основная программа ---------------------------------
void main()
{
DAT a;
do
{
scanf("%d%d%d", &a.day, &a.month, &a.year);
}
while(TestData(&a) ==0);
PlusData(&a, 17);
}
//--------------------------------------------------------
Фактически определение класса объектов как типа данных и известного набора функций для выполнения операций над переменными этого типа эквивалентно понятию базового типа данных (БТД) языка программирования. Единственное отличие класса от БТД заключается в том, что первый определяется программистом, а второй встроен в определение языка программирования.
Язык программирования Си++ представляет собой расширение языка Си для программирования объектов и их классов. При этом использование классов эквивалентно вплоть до синтаксиса использованию базовых типов данных:
Понятия классического Си Понятия Си++
------------------------- ----------- БТД: Класс:
элемент данных языка, для определяемая пользователем
которого известно множество структура, элементы которой
значений, форма представления, являются ранее определен набор операций. ными типами данных и классами,
и множества функций,оперирующих с ним.
--------------------------------------------------------- Переменная: Объект:
область памяти, содержащая переменная, содержащая
структуру данных определенного структуру данных, определенную
типа. как класс.
--------------------------------------------------------- Операция: Переопределение операторов:
операция над переменной интер- функция, определенная для объек претируется по отношению к тому тов указанного класса может быть
БТД, к которому относится пере- вызвана в виде одной из стандарт менная (так операция '+' ных операций языка Си, которая
по-разному интерпретируется для переопределяется, если операндом
переменных типа int и double). ее является объект класса, а не
переменная БТД.
Лекция 2. Дополнительные возможности языка Си++
-----------------------------------------------
Ниже рассмотрим средства, расширяющие классический Си. Хотя
они и не относятся непосредственно к классам, с их помощью можно
реализовать рассмотренные выше принципы объектно-ориентированного
программирования.
2.1. Присваивание структур
------------------------- Операция присваивания может быть применена к структурам одного типа. В этом случае предполагается их побайтное копирование
одной в другую. Она (а не ссылка на нее) может быть также фактическим параметром и результатом функции. Если имеется ссылка на
структуру с именем p, то результатом операции *p является структура в целом. Таким образом, структура приближается к базовым типам данных в том смысле, что над ней возможны вышеуказанные операции. Для обозначения структуры можно также использовать имя
структуры без ключевого слова struct.
struct dat
{ int day,month,year; }
dat NextDat(dat x) // Формальный параметр - структура
{ ... return(x); } // Возвратить структуру как результат
dat Nextdat1(dat *p)
{ ... return(*p); } // Возврат структуры косвенно по ссылке
dat a,b,c,*q; // Ключевое слово struct не используется
void main()
{
q = &b;
a = b; // Прямое присваивание структур
a = *q; // Косвенное присваивание по ссылке
c = NextDat(b); // Присваивание структуры как результата
c = NextDat1(&b); // функции, фактический параметр в
} // NextDat - копия структуры
2.2. Обращения по адресу (неявная ссылка)
----------------------------------------
При работе со структурами большого размера - при передаче их
в качестве параметров и результатов функций - копирование их является неэффективной операцией. Гораздо эффективнее передавать ссылку на эту структуру. Для того, чтобы постоянно не указывать операции взятия адреса и косвенного обращения по ссылке в Си++ введен тип - неявная ссылка: при определении переменной неявно вводится ссылка, указывающая на эту переменную. Использование этой переменной в большинстве операций предполагает косвенное обращение по соответствующей ссылке. При инициализации такой переменной значением другой переменной создается ссылка на эту другую переменную. При использовании в любом выражении переменной - неявной ссылки реально производится косвенное обращение по созданной ссылке.
Си++ Эквивалент в "классическом" Си
------------------------ -----------------------------//--------------- Инициализация константой -----------------int &a = 5; int a, *pa =a;
*pa = 5;
//--------------- Инициализация переменной -----------------int x; int x,*pa;
int &a = x; pa = &x;
a = 5; *pa = 5;
//-------------- Неявная ссылка на структуру ----------------struct dat struct dat
{ int day,month,year }; { int day,month, year };
dat x; dat x;
dat& b = x; dat* pb = &x;
dat& c = {12,12,1990}; dat cc = {12,12,1990};
dat *pc = &cc;
b.year = 1990; pb->year= 1990;
c.day=b.day+3; pc->day = pb->day+3;
c = b; // Копирование pc->day = pb->day;
// структуры pc->month = pb->month;
pc->year = pb->year;
Наиболее часто неявные ссылки используются при передаче параметров и результатов функций. В этом случае транслятор сам выбирает, что необходимо использовать в качестве фактического параметра - переменную или ссылку на нее, и что используется в качестве результата - ссылка или переменная, косвенно адресуемая по ссылке. Цель подобных ухищрений будет видна позднее - при переопределении операторов, а пока можно заметить, что вызов функций, с
параметрами - обычными значениями и неявными ссылками - синтаксически идентичен. То же самое касается результатов.
В качестве иллюстрации рассмотрим три примера функций, имеющих в качестве формального параметра и результата структуру, которая передается соответственно:
- значением;
- явной ссылкой;
- неявной ссылкой.
Пример 1. Параметры - значения
---------------------------------------------------------dat Inc(dat x) ========> - копирование
{ --------> - ссылка
x.day++;
return(x); ----¬ стек +---+x.day++
} ¦ b =========> x =========¬
L---- +---+ ¦ return(x)
void main() ¦
{ ----¬ стек +---+ --¦-¬ временная
dat a,b,*p; ¦ a <========= x <======= ¦ переменная
a = Inc(Inc(b)); L---- +---+ L---p = &Inc(b); x.day++
a = *p;
}
Пример 2. Параметры - явные ссылки
---------------------------------------------------------dat* Inc(dat* x) x->day++
{ x->day++
x->day++; ----¬ стек +---+
return(x); г===== b <--------- x ¦
} ¦ --> <----¬ +-¦-+
¦ ¦ L---- ¦ ¦return(x)
¦ ¦ г======+=====void main() a=*..¦ ¦ ¦ ¦ +---+ стек
{ ¦ ¦ --¦-¬ L---- x ¦
dat a,b,*p; ¦ ¦ ¦ =========> ¦
a = *Inc(Inc(&b)); ¦ ¦ L---- +-¦-+
p = Inc(&b); ¦ ¦ ----¬ ¦return(x)
a = *p; ¦ L-- <===========} ¦ L--- ¦ ----¬
L====> a ¦
L---
Пример 3. Параметры - неявные ссылки
---------------------------------------------------------dat& Inc(dat& x) x.day++ неявная ссылка dat* px
{ x.day++
x.day++; ----¬ стек +---+
return(x); г===== b <--------- px¦
} ¦ --> <----¬ +-¦-+
¦ ¦ L---- ¦ ¦return(px)
¦ ¦ г======+=====void main() a=*..¦ ¦ ¦ ¦ +---+ стек
{ ¦ ¦ --¦-¬ L---- px¦
dat a,b,*p; ¦ ¦ ¦ =========> ¦
a = Inc(Inc(b)); ¦ ¦ L---- +-¦-+
p = &Inc(b); ¦ ¦ ----¬ ¦return(px)
a = *p; ¦ L-- <===========} ¦ L--- ¦ ----¬
L====> a ¦
L---
Сравнение этих примеров показывает следующее:
- при работе с формальным параметром - неявной ссылкой используется имя формального параметра в качестве идентификатора переменной, которая заменяется транслятором на косвенное обращение по неявной ссылке;