Главная      Учебники - Разные     Лекции (разные) - часть 32

 

Поиск            

 

Объектно-Ориентированное программирование

 

             

Объектно-Ориентированное программирование

I. Развитие языков программирования

Определения:

ANSI – American National Standards Institute - Национальный Институт Стандартизации США

ISO - International Organization for Standardization - Международная организация по стандартизации

Цель развития языков программирования - более рациональная разработка ПП.

Схема развития:

Коды процессора а assembler а языки высокого уровня (ЯВУ)
Сначала из истории:

При разработке процессоров(П)/микропроцессоров – для каждого П разрабатывается набор команд, полный набор насчитывает ~150 команд: арифметика, логика, работа с памятью, ввод и вывод.

Команда для процессора – это цифровой код команды и операнд (операнды):

ячейки памяти, регистры, порты ввода/вывода...

Коды процессора – набор в цифровом коде команд процессора и их параметров, например, команды: занесение значения на регистр, вывод с регистра по адресу памяти, сложение, чтение байта из порта ввода, запись байта в порт вывода
Именно коды процессора содержит исполняемый файл программы файл (*.exe )

Разработка программ в кодах была характерна для самых первых ВМ – это очень неудобно для человека-программиста.

Assembler – низкоуровневый язык программирования, разработанный для конкретного процессора.

Assembler использует мнемоническое обозначение кодов команд процессора и переменных памяти, что облегчает процесс программирования по сравнению с кодированием:
JUMP - переход, ADD - сложение, IN - ввод, OUT – вывод, и т.д. для всех команд процессора.
Assembler позволяет использовать весь набор команд процессора и напрямую работать с регистрами.
Используется там, где необходима высокая эффективность: ядро ОС, драйверы, программы, работающие в реальном времени.

Недостатки – высокая трудоемкость разработки, привязка программы к конкретному типу процессора.

Языки высокого уровня – FORTRAN, ALGOL, COBOL, PL/I, ADA, Prolog, PASCAL, C, C++, Perl, JavaScript, ASP, PHP, Java, С#, SQL…

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

Среди ЯВУ есть специализация: научные расчеты (FORTRAN), для обучения (ранний Basic, Pascal), экономические рачеты (COBOL), работа с БД (dBase, FoxPRO, SQL) ,
целое семейство сравнительно молодых языков для Internet (JavaScript, ASP, PHP),
языки системного программирования (ранний С, assembler’ы).
Некоторые языки считаются универсальными (поздний Pascal (Delphi), C/C++)

II. Развитие технологий разработки программ
Схема:

Низкоуровневое программирование (коды, Assembler’s) а
аПроцедурное/Cтруктурное программирование (Algol, Pascal, C) а

аООП (C++,Object PASCAL, Java, C#…) а

а…(что дальше?)

Вспоминаем, как обстояло дело с разработкой программ в 60-е – 70-е годы,
технологическая ступенька называлась:

Процедурное программирование

Основная идея – выделение части кода в отдельную процедуру (подпрограмму, функцию) (SUBROUTINE в FORTRAN, PROCEDURE и FUNCTION в PASCAL).

Будем считать для нашего курса понятия процедура, подпрограмма и функция синонимами – так в Си есть только функция.
Функция обозначается именем, при вызове ей передается список параметров (возможно, пустой), после выполнения она возвращает управление в точку вызова и, возможно, возвращает результаты работы (вычисленные значения, код завершения).

Пример:
real sin(real x){

// здесь реализация

}

В процедурных языках поддерживается вызов процедур/подпрограмм/функций, который обычно включает такие механизмы:

  • передача параметров в процедуру и возврат значений,

  • рекурсивность, т.е. возможность процедуры вызывать саму себя (известная задача о Ханойской башне),

  • хранение подпрограмм в отдельных библиотеках.


Далее, технологическая ступенька начала 70-х годов:
Структурное программирование – основные положения:
любую программу можно написать, пользуясь ограниченным набором базовых конструкций (здесь схемы основныхконструкций структурного программирования, Павловская, стр 39):

  • Последовательность операторов/блоков,

  • Ветвление или выбор if, if..else, swith-case

  • Циклы: с постусловием (do while), цикл с предусловием (while)


Каждая из базовых конструкций имеет один вход и один выход.

Правильная” структура программы (блока программы, подпрограммы), имеет один вход и один выход.

Причем, любую программу можно и нужно писать без использования оператора GoTo, который очень запутывает структуру программы (аналог – команда перехода JMP в assembler).
Для исключения оператора GoTo достаточно применять базовые конструкции “цикл” - не всегда это удобно, но почти всегда оправдано.

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

Следование этим правилам при разработке программ и означало применение структурного подхода к программированию. Эти правила ограничивали “свободу” программистов (по сравнению с assembler и Fortran), но позволяли писать более понятные, простые, надежные программы. Улучшился контроль над кодом, стала возможна реализация более крупных проектов.

На базе принципов структурного программирования (СП) был создан новый, элегантный язык PASCAL (примерно 1968 г, Никлаус Вирт)
Проанализируем программирование на PASCAL с позиций СП.
Базовые конструкции СП внесены в язык: IF..[ELSE], CASE, WHILE, REPEAT..UNTIL.
Для описания сложных типов данных в языке есть массивы, записи (RECORD), множества.

!Важно:

Структура программы на Pascal состоит из разделов:

  • Uses - включение модулей

  • Const – раздел констант

  • Type – описание новых типов данных (конструирование)

  • Var – объявление (выделение памяти под реальные переменные)

  • Процедуры – реализуют автономные фрагменты вычислений

  • Главная программа – Реализует полный алгоритм решения задачи.

PASCAL жестко навязывал программистам использование стиля СП – это был переход на новый технологический уровень в разработке программ общего назначения (обработка данных, научные расчеты) – это был технологический прорыв.
Пожалуй, все последующие реализации ЯВУ, включали конструкции СП.
Разработка в стиле СП имеет накладные расходы (по сравнению с assembler), код программы получается больше за счет избыточных проверок в циклах и отсутсвия GoTo – это был основной аргумент противников СП (в основном, противниками были программисты на assemblere).


Cтруктурное программирование на С/С++

На прошлом занятии говорили о СП, акцентировали основные положения:
процедурное П, П с исп. базовых конструкций СП, структура программы на PASCAL.

Сложнее всего следовать стилю СП было на assembler’s.

Язык С(Си) создан в конце 60-х - начале 70-х для разработки системного ПО в рамках проекта ОС Unix (Деннис Ричи – один из авторов).

С включает конструкции СП, в нем реализован механизм построения сложных структур данных.

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

С дает большую свободу действий, но требует от программиста большей самодисциплины.
Многие программисты на assembler в 80-е годы перешли на C.

В настоящее время С универсальный язык программирования для разработки системного ПО (Unix и Windows), графических интерфейсов, сложного прикладного ПО (например, СУБД) - задач, где необходима эффективность выполнения программ.

С – распространен, компиляторы реализованы в большинстве ОС.

В каждой реализации UNIX есть компилятор С/С++ как важная часть ОС.
C++ является объектно-ориентированным расширением языка C.

Первая широко известная реализация принципов ООП – это описание языка С++, начало 80-х, автором является Бьярне Страуструп.

Кроме компиляторов в каждой Unix-подобной системе распространены компиляторы
Borland C++ и Microsoft C++ для платформы Windows,

В 1997 г был принят международный стандарт ANSI C/C++ - итог 20-тилетнего развития

Существующий стандарт ANSI C++ - это классическое описание ООП.

Сейчас язык С++ является языком публикаций по вопросам ООП.

Практикум на С/С++:
Фактически С++ содержит 2 языка:
Полностью включает низкоуровневый Си, поддерживающий конструкции СП, и, собственно, С++ (Си с классами) – язык объектно-ориентированного программирования (ООП).

Мы находимся сейчас на технологической ступени структурного программирования, поэтому начинаем с Си:

Знакомство с С, некоторые конструкции СП:


0.Программа выводит на экран строку "Hello? World".

#include // подключение заголовочного файла, в котором описаны функции i/o printf и getc

void main(){ // в программе всегда д.б. функция main, с нее начинается выполнение

printf("Hello, World!");

getc();

}

1.// Комментарий до конца строки

/* Комментарий много-

строчный. В С/С++ отличаются прописные и строчные буквы.

*/


2.Операторные скобки {} задают программный блок.


int i=5; // выделение памяти и присваивание значения
{

int i=7;

..

if(i<7){...}; // не выполнится

}

if(i<7){...} // выполнится

// i внутри блока и i вне блока – это разные переменные


3. Цикл
for(int i=0; i<100; i++){

...

if(...)

break; // прервать цикл

}


if(i<99){...} //error, i не определено


4. Условный оператор

bool fOk=true; // true/false

int a, b=7;

...

fOk=(a==b); // вычисляется логическое значение a==b и присваивается

...

if(fOk){

//... выполняется, когда логическое выражение true

}

else{

//... выполняется, когда логическое выражение false

}


5. Цикл с постусловием и выбор.


char c; // 1 byte

bool fOk;

do{ // Начало цикла с постусловием

fOk=true;

printf(”Вы любите программировать?\n”);

printf(”Ответ Д/Н/?:”);

c=getc();


switch(c){ //

case ‘Д’: printf(“Yes, sir”);

break;

case ‘Н’: printf(“No”);

break;

case ‘?’: printf(“Не знаю”);

break;

default:

printf(“*Ошибка, повторите ввод”);

fOk=false;

}

}

while(!fOk); // Конец цикла с постусловием


6. Структуры.
Структуры в Си служат для конструирования новых типов сложных данных
(Павловская с.67, Березин. с 124)
struct Student{ // описание нового типа данных Student

char Name[51];

int Age;

char Course;

char Group[4]; // ПЭ2х
float Ball; //Average; // Средняя оценка

float S; // Стипендия

}; //! Важно, в конце описания структуры ставится точка-с-запятой;


Student S1, S2; // Объявление двух переменных (выделение памяти)

// Занесение значений в элементы структуры:

S1.Age=21;

S1.Kurs='2';

S1.S=550.5;

strcpy(S1.Name,"Мистер Х."); // Копирование строки в строку структуры


Student PE21[50]; // Массив структур

strcpy(PE21[0].Name,"Lady Y");

PE21[0].Age=17;

...

for(int i=0; i<50; i++){ // Начисление стипендии

if(PE21[i].Ball>=4.0)

PE21[i].S=400.0;

else

PE21[i].S=0.0;

}

Недостатки массивов – жесткие рамки

Усложнения:
Повышенная стипендия при 4.5
Расчет среднего бала по группе

расчет суммы стипендии по группе


C/C++ Функция. Модуль. Проект. Заголовочный файл.


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

Процедура – выполняет часть кода, не обязательно возвращает результат.


В С/С++ нет процедур – только функции. Функции не могут быть вложенными.

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


[<тип возвр.значения>] <имя функции>([список параметров]){

// тело функции (body)

return [<возврашаемое значение>];

}

Для каждого параметра в списке указывается тип.
Оператор return прекращает выполнение функции и возвращает управление в точку вызова.
С помощью return функция может вернуть вычисленное значение.

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


// Пример функции вычисления среднего:

float Average(float a, float b){

return (a+b)/2;

}

void main(){

//…

float A=10.5, B=11.7, C=0.0;

C=Average(A, B); // Вызов функции

//…

}

Любая функция (кроме main) должна быть описана в тексте программы до момента ее вызова.

В качестве описания можно применить объявление прототипа (прототип/заголовок/интерфейс функции - синонимы), т.е. указать имя функции, список передаваемых параметров и тип возвращаемого значения, например:
float Average(float a, float b); // Прототип функции вычисления среднего


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

В С++ допустимо иметь несколько функций с одинаковым именем и различающимися списками параметров (это проявление полиморфизма), например:

int Summ(int A, int B); // вычисление суммы для int

float Summ(float A, float B); // вычисление суммы для float


В программе С/С++ должна быть функция main (главная) – именно она вызывается при запуске программы на выполнение:

int main(int argc, char* argv[]){ // ДЗ: разобраться с параметрами main

// int argc – число параметров в командной строке
//
char* argv[] – массив строк, где каждая строка – параметр из
// командной строки.
argv[0] – имя программы.
//...
Здесь реализация, и возврат значения, например так:

if(fOk)

return 0; //возвращение кода завершения

else

return -1; //возвращение кода завершения

}

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


Параметр, или аргумент – это значение, передаваемое в функцию.

При разработке функций используются имена параметров, которые являются формальными (условными).

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

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


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

Это неудобно в следующих случаях:

  • когда передается большой массив, структура (создание копии параметра занимает много времени и памяти).

  • когда нужно изменить значение параметра внутри функции и вернуть его вызывающей программе