1.34k likes | 1.62k Views
Программирование. Часть 6 . Основы ООП Динамические структуры данных. 5. Объектно-ориентированное программирование 5. 1 . Декомпозиция: divide et impera. Современные программные системы – сложные системы: они отражают сложность реального мира;
E N D
Программирование Часть 6. Основы ООП Динамические структуры данных
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Современные программные системы – сложные системы: • они отражают сложность реального мира; • процесс их разработки сложен (и слабо стандартизирован); • программа - дискретная система, а дискретные системы неустойчивы: маленькая ошибка приводит к значительным последствиям. • Общие свойства сложных систем: • Имеют внутреннюю структуру, то есть состоят изкомпонент - подсистем, которые, в свою очередь, тоже могут быть разбиты на подсистемы. • Внутренние связи подсистем сильнее связей между этими подсистемами. Это дает возможность по отдельности изучать каждую часть. • Состоят из ограниченного числа типов подсистем, скомбинированных и организованных различным образом. • Являются результатом эволюции более простых систем.
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Рост сложности и объема ПО на примере ОС Windows (неофициальные данные): • Последствия ошибок: • Состоят из ограниченного числа типов подсистем, скомбинированных и организованных различным образом. • Являются результатом эволюции более простых систем.
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Сложности разработки: • Служба Microsoft Consulting Services провела анализ результатов выполнения большого количества своих программных проектов. • Оказалось, что вероятность провала программных проектов довольно велика. • Только 24% проектов можно признать в той или иной степени успешными, • 26% не были завершены, • 50% столкнулись с большими проблемами, например, бюджет был превышен вдвое или затрачено в 1,5 раза больше времени.
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Последствия маленьких ошибок – крах программной системы: • 1996 год. • Ошибка взятия целой части дробного числапри выходе числа с плавающей точкой за диапазон допустимых 16-битовых целых: • double x; • … • short i = x; • …Вместо: • double x; • … • if (abs (x) < 32 767) short i = x; • else …; • Результат:
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera 4 июня 1996 года Взрыв ракеты-носителя Ariane 5 спустя 30 секунд после запуска.
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Способ преодоления сложности – декомпозиция • При проектировании сложной программной системы необходимо разделять ее на все меньшие и меньшие подсистемы, каждую из которых можно совершенствовать независимо. • Построив модели ограниченного числа подсистем, можно, комбинируя их различным образом, строить множество гораздо более сложных систем. • Построив более простую модель, ее можно далее развивать, следуя за развитием системы. • В этом случае мы не превысим пропускную способность человеческого мозга: для понимания любого уровня системы необходимо держать в памяти информацию лишь о немногих частях системы.
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Алгоритмическая декомпозиция • Основана на разделении алгоритмов по модулям системы. • Каждый модуль выполняет один из этапов общего процесса. • Реализуется средствами структурного программирования • Объектно-ориентированная декомпозиция • Мир представляется совокупностью автономно действующих объектов, моделирующих объекты реального мира. • Каждый объект обладает своим собственным поведением. • Послав объекту сообщение, можно попросить его выполнить присущее ему действие. • Объекты взаимодействуют друг с другом, моделируя поведение системы, соответствующее более высокому уровню. • Реализуется средствами объектно-ориентированного программирования.
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Объектно-ориентированное программирование (ООП) – методология программирования, основанная на представлении программы в виде совокупности объектов, каждый из которых является экземпляром определенного класса, а классы могут образовывать иерархию наследования.
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Иерархическое упорядочение задач или объектов – важный принцип управления сложностью проекта, лежащий в основе объектно-ориентированного подхода. • Структурная иерархия строится по простому принципу разделения целого на составные части: Животное Голова Туловище Глаза Уши Рот Лапы Хвост … …
5. Объектно-ориентированное программирование 5.1. Декомпозиция: divide et impera • Объектная иерархия строится по принципу наследования свойств родительских (вышележащих) классов объектов дочерними (нижележащими) классами. • Родительские классы называют просто родителями (предками), дочерние – потомками • Птица, собака, волк – это типы животных, называемые классами. • Конкретная реализация того или иного класса, например, кот Матроскин, является объектом данного класса. Животное Птица Млекопитающее Собака Волк Воробей Кошка Орел … …
5. Объектно-ориентированное программирование 5.2. Три принципа ООП • Объект характеризуется: • совокупностью своих элементов (и их текущих значений • совокупностью допустимых для объекта действий • Объединение в едином объекте «материальных» составных частей (обрабатываемых данных), защищенных от внешних воздействий, и действий, манипулирующих этими частями (данными) называют инкапсуляцией. • Наследование – это такое отношение между объектами, когда дочерний объект повторяет элементы структуры и поведения родительского. • Классы верхних уровней обычно не имеют конкретных экземпляров объектов. (Не существует конкретного живого организма, который назывался бы млекопитающее Бобик). Такие классы называют абстрактными. • Конкретные экземпляры объектов относятся, как правило, к классам самых нижних уровней объектной иерархии (собака Бобик, кот Матроскин). • Полиморфизм – это свойство различных объектов выполнять одно и то же действие (с одним и тем же названием) по-своему. • Родительские типы называют просто родителями (предками), дочерние – потомками
5. Объектно-ориентированное программирование 5.3. Инкапсуляция • Инкапсуляция – механизм, связывающий воедино программный код и данные, которыми он манипулирует, а также обеспечивающий их защиту от внешнего вмешательства и неправильного использования. • Класс – определенный пользователем проблемно-ориентированный тип данных, описывающий внутреннюю структуру объектов, которые являются его экземплярами. • Объект (экземпляр класса) находится в таком же отношении к своему классу, в каком переменная находится по отношению к своему типу. • Данные и функции внутри класса называются членами класса. • Данные, входящие в класс, называются данными-членами или полями. • Функции, принадлежащие классу, называют функциями-членами или методами.
5. Объектно-ориентированное программирование 5.3. Инкапсуляция • Синтаксис объявления класса, который не является наследником никакого другого класса: • class Имя_Класса • { • закрытые данные и функции • спецификатор доступа: • данные и функции • спецификатор доступа: • данные и функции • … • спецификатор доступа: • данные и функции • }; Имя_Класса Данные Функции
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Пример описания простейшего класса, включающего только данные: class СBox { public: double m_length; double m_width; double m_height; }; m_height m_length m_width
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Пример описания простейшего класса, включающего только данные: class СBox { public: double m_length; double m_width; double m_height; }; Спецификатор доступа
5. Объектно-ориентированное программирование 5.3. Инкапсуляция • Спецификатор доступа определяет, где в программе будут доступны описанные за ним члены класса. • Имеются 3 спецификатора доступа: • Public – члены класса будут доступны как в классе, так и в любой точке программы внутри области видимости класса, к которому они относятся. • Private (спецификатор по умолчанию) – члены класса будут доступны только внутри класса (членам класса) • Protected – члены класса будут доступны только внутри класса и внутри потомков класса • Действие спецификатора доступа распространяется до следующего спецификатора или до конца описания класса • По умолчанию, все члены класса, объявленные после ключевого слова class до первого спецификатора доступа имеют спецификацию доступа private
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Объявление экземпляров класса CBox mybox1, mybox2; Объявление указателей на класс CBox *pbox; pbox=&mybox1; Динамическое выделение памяти для экземпляра класса CBox *pmybox = new CBox; Доступ к членам – аналогично структурам mybox1.m_length = 2.5; mybox2.m_width = mybox1.m_length; pmybox->m_height = mybox1.m_length; pmybox->m_length = pmybox->m_height ;
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Первый принцип инкапсуляции: объединение данных и методов. Добавим функцию вычисления объема class СBox { public: double m_length; double m_width; double m_height; double Volume( ); }; double CBox::Volume() { return m_length*m_width*m_height; }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Поработаем с классом CBox int main() // Working with class CBox { CBox mybox1; // Static allocation mybox1.m_length=2; mybox1.m_width=3; mybox1.m_height=4; cout << mybox1.Volume() << endl; // 24 CBox *pmybox2 = new CBox; // Dynamic allocation pmybox2->m_length=5; pmybox2->m_width=6; pmybox2->m_height=7; cout << pmybox2->Volume() << endl; // 210 delete pmybox2; return 0; }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Второй принцип инкапсуляции: защита от внешнего вмешательства. Доступ к данным через явный интерфейс class CBox { double m_length; double m_width; double m_height; public: void Setlength(double sl) {m_length = sl; } void Setwidth(double sw) {m_width=sw; } void Setheight(double sh) {m_height =sh; } double Getlength() {return m_length;} double Getwidth() {return m_width;} double Getheight() {return m_height;} double Volume( ); };
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Работаем с измененным классом CBox: int main() // Working with modified class CBox { CBox mybox1; mybox1.Setlength(2); mybox1.Setwidth(3); mybox1.Setheight(4); cout << mybox1.Getheight() << " " << mybox1.Volume() << endl; // 4 24 CBox *pmybox2 = new CBox; pmybox2->Setlength(5); pmybox2->Setwidth(6); pmybox2->Setheight(7); cout << pmybox2->Getlength() << " " << pmybox2->Volume() << endl; delete pmybox2; return 0; }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Для чего это нужно: независимость интерфейса от реализации, разрешаются только операции, определенные через интерфейс class CBox { double m_Size[3]; //now with array !!! public: void Setlength(double sl) {m_Size[0] = sl; } void Setwidth(double sw) {m_Size[1]=sw; } void Setheight(double sh) {m_Size[2] =sh; } double Getlength() {return m_Size[0];} double Getwidth() {return m_Size[1];} double Getheight() {return m_Size[2];} double Volume( ); }; double CBox::Volume() { return Getlength()*Getwidth()*Getheight(); }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция В использующей класс программе ничего менять не надо: int main() // Working with modified class CBox { CBox mybox1; mybox1.Setlength(2); mybox1.Setwidth(3); mybox1.Setheight(4); cout << mybox1.Getheight() << " " << mybox1.Volume() << endl; CBox *pmybox2 = new CBox; pmybox2->Setlength(5); pmybox2->Setwidth(6); pmybox2->Setheight(7); cout << pmybox2->Getlength() << " " << pmybox2->Volume() << endl; delete pmybox2; return 0; }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция • Конструкторы • Конструктор класса – специальная функция класса, которая вызывается при создании нового объекта класса. Она позволяет инициализировать объекты во время их создания и захватывать ресурсы, необходимые для их функционирования. • Конструкторы всегда называются по имени класса и не имеют типа возврата. • Компилятор предоставляет два типа конструкторов: конструктор по умолчанию и конструктор копирования: • CBox mybox1; // Вызов конструктора по умолчанию • … • CBox mybox2 = mybox1 // Вызов конструктора копирования • Класс может иметь несколько конструкторов, которые можно перегружать • Если Вы определили какой-либо свой конструктор копирования, Вы обязаны явно определить конструктор по умолчанию. • Стандартный конструктор копирования нельзя использовать при работе с указателями
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Класс Cboxс перегруженным конструктором и тестовым деструктором class CBox { double m_length; double m_width; double m_height; public: CBox() {m_length=0; m_width=0; m_height=0;} CBox(double l,double w) {m_length=l; m_width=w; m_height=0;} CBox(double l, double w, double h){m_length=l; m_width=w; m_height=h;} ~CBox () {std::cout << "destructor CBox done";} void Setlength(double sl) {m_length = sl;} void Setwidth(double sw) {m_width=sw;} void Setheight(double sh) {m_height =sh;} double Getlength() {return m_length;} double Getwidth() {return m_width;} double Getheight() {return m_height;} void Print (){std::cout <<"\nL="<<m_length<<" W="<<m_width<<" H="<<m_height;} double Volume( ){return m_length*m_width*m_height;} };
5. Объектно-ориентированное программирование 5.3. Инкапсуляция В конструкторе инициализацию переменных-членов класса можно делать в теле конструктора: CBox() {m_length=0; m_width=0; m_height=0;} CBox(double l,double w) {m_length=l; m_width=w; m_height=0;} CBox(double l, double w, double h){m_length=l; m_width=w; m_height=h;} Или вне тела: CBox() : m_length(0), m_width(0), m_height(0) { } CBox(double l,double w): m_length(l), m_width(w), m_height(0) { } CBox(double l, double w, double h): m_length(l), m_width(w), m_height(h) { }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Поработаем с этим классом int main() // Working with class CBox { CBox mybox1; mybox1.Print(); // L=0 W=0 H=0 CBox mybox2(1,2,3); mybox2.Print(); // L=1 W=2 H=3 CBox mybox3(1,2); mybox3.Print(); // L=1 W=2 H=0 CBox mybox4=mybox2; mybox4.Print(); // L=1 W=2 H=3 mybox1=mybox2; mybox1.Print(); // L=1 W=2 H=3 _getch(); return 0;// Destructor done }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Стандартный конструктор копирования нельзя использовать, если Вы работаете с членами - указателями class CPoint { short m_a; short *m_k; public: CPoint() {m_a=4; m_k=new short (1);} // Consructor ~CPoint() {delete m_k; m_k=NULL;} // Destructor void Setk(short k){*m_k=k;} void Seta(short a){m_a=a;} void Print () {std::cout << "\n a="<<m_a<<" k=" << m_k<< " *k="<<*m_k;} };
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Стандартный конструктор копирования нельзя использовать, если Вы работаете с членами - указателями int main() // Working with class CPoint { CPointx; x.Print(); // a= 4 k=003B6188 *k=1 CPoint y=x; y.Print();// a= 4 k=003B6188 *k=1 x.Setk(5); x.Seta(8); x.Print(); // a= 8 k=003B6188 *k=5 y.Print(); // a= 4 k=003B6188 *k=5 return 0; // program crash while try to free the same } // memory second time!
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Надо определить свой конструктор копирования class CPoint { short m_a; short *m_k; public: CPoint() {m_a=4; m_k=new short (1);} CPoint (const CPoint &p) {m_a=p.m_a; m_k=new short(*p.m_k);} ~CPoint() {delete m_k; m_k=NULL;} void SetK(short k){*m_k=k;} void SetA(short a){m_a=a;} void Print () {std::cout << "\n a="<<m_a<<" k=" << m_k<< " *k="<<*m_k;} }; Если передавать p не по ссылке, а по значению, произойдет зацикливание функции, так как передача по значению предполагает создание нового объекта и копирование значения, которое тоже выполняется с помощью этой функции const, чтобы Вы по глупости не изменили значения полей источника в функции при их копировании
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Та же программа, теперь дает ожидаемый результат int main() // Working with class CPoint { CPointx; x.Print(); // a= 4 k=003B6188 *k=1 CPoint y=x; y.Print();// a= 4 k=003B6260*k=1 x.SetK(5); x.SetA(8); x.Print(); // a= 8 k=003B6188 *k=5 y.Print(); // a= 4 k=003B6260*k=1 return 0; }
5. Объектно-ориентированное программирование 5.3. Инкапсуляция • Деструкторы • Деструктор класса – специальная функция класса, которая уничтожает объект, когда необходимость в нем отпадает или время его жизни завершено. • Имя деструктора совпадает с именем класса, которому предшествует знак ~(тильда). • Деструктор не принимает параметров и не возвращает значения. Таким образом, деструктор в классе всегда один. • Компилятор предоставляет деструктор по умолчанию. • Однако, если Вы захватывали какие-либо ресурсы при создании объекта (например, динамически выделяли память), Вы обязаны переопределить деструктор для корректного освобождения ресурсов • Это было сделано в предыдущем примере: • ~CPoint() {delete m_k; m_k=NULL;}
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Объекты в памяти CBox box1, box2, box3 box3 box1 box2 m_length m_length m_length m_width m_width m_width m_height m_height m_height Setlength() Getlength() Setwidth() Getwidth() Setheight() Getheight() Volume()
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Указатель this double CBox::Volume() { return m_length * m_width * m_height; } box1.Volume(); box2.Volume(); box3.volume() double CBox::Volume(const CBox* this) { return this->m_length * this->m_width * this->m_height; } CBox::Volume(&box1);
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Статические переменныеили константы - члены класса class CBox { double m_length; double m_width; double m_height; static int m_noboxes; public: CBox() {m_length=0; m_width=0; m_height=0;m_noboxes++} void Setlength(double sl) {m_length = sl; } void Setwidth(double sw) {m_width=sw; } void Setheight(double sh) {m_height =sh; } double Getlength() {return m_length;} double Getwidth() {return m_width;} double Getheight() {return m_height;} double Volume( ); }; Статические данные-члены класса только объявляются внутри класса. Они должны быть определены вне класса следующим образом: int CBox::m_noboxes; // или int CBox::m_noboxes=0;
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Объекты в памяти CBox box1, box2, box3; box3 box1 box2 m_length m_length m_length m_width m_width m_width m_height m_height m_height Setlength() Getlength() Getwidth() Setwidth() Getheight() Setheight() m_noboxes Volume()
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Статические функции - члены класса class CBox { double m_length; double m_width; double m_height; static int m_noboxes; public: CBox() {m_length=0; m_width=0; m_height=0;m_noboxes++} void Setlength(double sl) {m_length = sl; } void Setwidth(double sw) {m_width=sw; } void Setheight(double sh) {m_height =sh; } double Getlength() {return m_length;} double Getwidth() {return m_width;} double Getheight() {return m_height;} double Volume( ); static Getnoboxes() {return m_noboxes;} }; Статические функции-члены класса имеют доступ только к статическим членам класса. Для доступа к нестатическим членам они должны получить адрес объекта как параметр
5. Объектно-ориентированное программирование 5.3. Инкапсуляция Константные объекты const CBox bx1(10, 15, 6); Константные функции-члены класса class CBox { double m_length; double m_width; double m_height; static int m_noboxes; public: const double Getlength() {return m_length;} const double Getwidth() {return m_width;} const double Getheight() {return m_height;} const double Volume( ); }; Значения полей константного объекта после инициализации не могут изменяться Константная функция не может изменять значения переменных-членов класса
Inf Inf Inf Inf link link link link 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Организация связанных структур данных. struct Node { Node *link; // Информационная часть inf // … };
Inf Inf Inf Inf link link link link inf inf inf link1 link1 link1 link2 link2 link2 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Основные виды связанных динамических структур данных: Линейные списки – данные динамической структуры, которые представляют собой совокупность линейно связанных однородных элементов, для которых разрешается добавлять элементы между любыми двумя другими и удалять любой элемент.
inf inf inf inf inf inf inf inf link link link link link link link link 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Основные виды связанных динамических структур данных: Кольцевые списки – имеют дополнительную связь между первым и последним элементами. Очередь – частный случай линейного списка – разрешено только 2 действия – добавление элементов в конец (хвост) и удаление из начала (головы) списка. Стек – частный случай линейного списка – разрешено только 2 действия – добавление и удаление элементов с одного конца (головы) стека.
inf inf inf inf inf inf inf inf link1 link1 link1 link1 link1 link1 link1 link1 link2 link2 link2 link2 link2 link2 link2 link2 5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Основные виды связанных динамических структур данных: Деревья – иерархические динамические структуры произвольной конфигурации.
5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Стек как объект-контейнер class CStack { struct m_Node { m_Node *m_next; int m_item; }; m_Node *m_head; int m_size; public: CStack() {m_head=NULL; m_size=0;} //Constructor ~CStack(); // Destructor void Push(int item); int Pull(); void Print(); };
5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Работа со стеком 1. Исходное состояние CStack() {m_head=NULL; m_size=0;} m_head m_size=0 2. Добавление элемента void CStack::Push(int item) { m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return; } m_head cur m_item m_next
5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Работа со стеком 1. Исходное состояние CStack() {m_head=NULL; m_size=0;} m_head m_size=0 2. Добавление элемента void CStack::Push(int item) { m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return; } m_head cur m_item m_next
5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Работа со стеком 1. Исходное состояние CStack() {m_head=NULL; m_size=0;} m_head m_size=0 2. Добавление элемента void CStack::Push(int item) { m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return; } m_head cur m_item m_next
5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Работа со стеком 1. Исходное состояние CStack() {m_head=NULL; m_size=0;} m_head m_size=0 2. Добавление элемента void CStack::Push(int item) { m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return; } m_head cur m_item m_next
5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Работа со стеком 1. Исходное состояние CStack() {m_head=NULL; m_size=0;} m_head m_size=1 2. Добавление элемента void CStack::Push(int item) { m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return; } m_head cur m_item m_next
5. Объектно-ориентированное программирование 5.4. Связанные динамические структуры данных Работа со стеком 1. Исходное состояние CStack() {m_head=NULL; m_size=0;} m_head m_size=1 2. Добавление элемента void CStack::Push(int item) { m_Node *cur=new m_Node; cur->m_item = item; cur->m_next = m_head; m_head = cur; m_size++; return; } m_head m_item m_next