ООП. Пособие по ООП в С++. Создание сложных программных систем Объектно ориентированная технология
Скачать 2.1 Mb.
|
Класс характеризуется наличием хотя бы одной абстрактной чисто виртуальной функции. Формат чисто виртуальной функции virtual тип Имя (параметры)=0; Каждый производный класс должен определить свою версию реализации чисто виртуальной функции. Использовать абстрактную функцию и создавать объекты абстрактного класса нельзя. Можно создавать указатель на объект абстрактного класса и применять для него механизм полиморфизма. Чистая виртуальная функция полезна, когда у нас есть функция, которую мы хотим поместить в родительский класс, но реализацию оставить дочерним классам. Чистая виртуальная функция абстрактного родительского класса вынуждает дочерние классы переопределить эту функцию, иначе объекты этих классов создавать будет невозможно. Пример. Иерархия списковых классов. Определение структур Очередь, Стек и Дек основано на определении Списка. Так как это линейные структуры, то у них один набор базовых операций: вставить, удалить, получить доступ. сlass TList //Список { protected: Tnode *L; Int n; public: TList(){n=0;L=0;} TList(); virtual void Ins(Tinfo d)=0; virtual void del(int pos)=0; void print(); }; Class TQuele:public TList //очередь { Public: TQuele (){n=0;L=0;} TQuele (); void Ins(Tinfo d) {реализация метода} void del(int pos=0) {реализация метода}; }; class TStek:public TList { public: TStek (){n=0;L=0;} TStek (); void Ins(Tinfo d) {реализация метода}; void del(int pos) {реализация метода}; }; main() { TList O; TList *a[3]; a[1]=new TQuele(); a[1]->Ins(10); a[1]->Ins(11); a[2]=new TStek(); a[2]->Ins(10); a[2]->Ins(11); } 10 Шаблонные классы Параметризованный класс, тип данных в класс передается как параметр. Определение шаблонного класса template class Имя { T info;// поле типа Т T Имя метода(T x); //функция типа Т и параметр типа Т } где Объявление экземпляров шаблонного класса Типы классу передаются при создании экземпляра (объявлении переменной типа класс). Объявление связывает тип с экземпляром класса. Имя класса <тип> имя экземпляра; Пример – шаблон - массива, конструктор с одним параметром #include { private: T *x; int n; public: massiv(){n=0;x=0;} massiv(int n1){n=n1;x=new T[n];} T* getx(); void set_x(int n1, T* x); }; template T* massiv { return x; } template {int i; if(n && (n==n1)) { for(i=0; i } int _tmain(int argc, _TCHAR* argv[]) { massiv Пример шаблон - класс- массив, конструктор с несколькоми параметрами #include template class A { private: T1 a; T2 b; public: A(){a=0;b=10;} T2 getb(); T1 geta(); }; template T2 A { return b; } template T1 A { return a; } int main() { A Определение методов шаблонного класса Реализуются вне класса, как шаблонные функции с параметром класса template { int i; if(n && (n==n1)) { for(i=0; i } Использование шаблона Все ссылки на класс, как тип данных, должны включать тип параметра в <имя типа>. void massiv Пример реализация перегрузки операций для шаблона. #include { private: int n; T *x; public: massiv( int n1){x= new T[n1]; n=n1;} massiv(){x=0; n=0;} massiv( const massiv &O); int getN(); void operator +(massiv &O1) { for ( int i=0; i T& operator []( int i); void operator *(int a); void inp(); massiv& operator =( const massiv &O) { if (&O== this ) return *this; if (x) delete []x; if (O.n) { n=O.n; x= new T[n]; for ( int i=0;i { x=0;n=0; } return *this; } }; template { if (n) { for ( int i=0;i } else cerr<<"No Object create"; } template T& massiv operator []( int i) { if (i<0 || i>=n) cerr<< "Oshibka" ; return *(x+i); } template { return n; } template const massiv { * this =massiv(O.n); for ( int i=0;i operator -( int a) //из объекта вычисляется число, объект при вызове слева { for ( int i=0; i *(T a, massiv //внешняя, так как мы хотим использовать константу и перед объектом 2*О { massiv ( int i=0;i } template operator *( int a) // объект при вызове слева О*2 { for ( int i=0; i /*massiv operator +(massiv &O1,massiv &O2) { massiv O(O1.n); for (int i=0; i }*/ template <<(ostream &os,massiv //внешняя { os<<"Перегрузка <<"; for ( int i=0;i >>(istream &is,massiv //внешняя { for ( int i=0;i Контейнерные_классы_11.1_Определение'>11 Контейнерные классы 11.1 Определение Конейнер - объект, назначением которого является хранение объектов других типов и управление ими. Контейнер представляет определение некоторой структуры данных, которая реализуется как шаблонный класс. Классическим примером контейнеров являются списки, векторы, массивы. Иногда содержимое контейнеров называют последовательностями. Контейнерные классы – распостраненный прием разработки классов, использующих механизм композиции и наполнения для подключения некоторых объектов к управляющему объекту – контейнеру. Контейнерный класс содержит в своем определении несколько объектных полей или указателей на объекты. Если контейнерный класс использует метод композиции, то тип и количество управляемых объектов фиксированы. Если используется метод наполнения то подключение реализуется через указатель, следовательно контейнер может управлять как объектами некоторого базового типа, так и объектами наследниками этого класса. Так как контейнер представляет объект управления некоторой структурой объектов, то основной операцией контейнера является последовательная обработка объектов (доступ к объектам в cтруктуре). Такая обработка обеспечивается двумя способами: Первый базируется на специальной процедуре просмотра всех элементов контейнера. В эту функцию передается функция, реализующая алгоритм требуемой обработки элемента контейнера. Второй реализуется через определение итератора или класса итераторов, подходящего для данного вида контейнера. При помощи итератора может управлять контейнером, не зная фактических типов, используемых для идентификации элементов. Итератор должен обеспечить возможность реализации циклических действий вида Цикл Пока очередной элемент определен Выполнить обработку элемента Перейти к следующему элементу Конец Пока Поэтому итератор состоит из трех частей: • - метод позволяющий выполнить обработку с первого элемента • - метод, организующий переход к следующему элементу • - метод, позволяющий проверить окончание данных. Доступ к очередной порции данных при этом осуществляется через специальный указатель текущей порции данных (указатель на объект класса- элемента). 11.2 Библиотека шаблонов STL Это набор шаблонных классов и функций, реализующих многие популярные структуры данных и алгоритмы. Т.к. STL состоит из шаблонных классов и функций, то структуры данных и алгоритмы могут применяться к любым типам данных – в этом мощь STL. STL поддерживается: контейнерами, алгоритмами. Алгоритмы применяются к контейнерам через итераторы, а так же через другие стандартные элементы: аллокатор, функциональные объекты, привязки и отрицатели. Контейнер – это объект, который содержит другие объекты. (массив объектов). 11.3 Виды контейнеров Последовательные – реализуют последовательности значений – линейные структуры. Ассоциативные – таблицы, обеспечивающие эффективное извлечение значений на основе ключей. Объекты контейнера хранят пару: ключ-значение. 11.4 Алгоритмы Применяются к контейнерам: инициализация, поиск в К, сортировка в К, слияние К-ов, изменение содержимого контейнера. Не модифицирующие операции над последовательностями: кол-во элементов в контейнере (последовательности); количество элементов, удовлетворяющих условию; поиск подпоследовательности в последователности, первое вхождение элемента, применение алгоритма к диапазону значений (for …each). Модифицирующие операции над последовательностями: • Копировать последовательность – copy • Копирует наоборот – copy_backward • Заполнение части последовательности –fiel • Присваивание элементам последовательности генерируемое функцией значение – generate • Меняет местами элементы, указанные итераторами – iter_swap • Упорядочение последовательности расставляя элементы так: сначала все элементы для которых предикат ИСТИНА, а затем те, для которых ЛОЖЬ -partition. • И многие другие. Операции сортировки и необходимые ей алгоритмы: бинарный поиск; диапазон, в который элемент может быть вставлен без нарушения порядка следования элементов; входит ли одна последовательность в другую; сортировка диапазона; минимальное и максимальное двух значений; итератор на максимальный в последовательности. 11.5 Итераторы Итератор – объект, который играет «как бы » роль указателя на элемент контейнера. Позволяют перемещаться по элементам контейнера. 5 типов итераторов: Произвольного доступа – сохраняет и извлекает элементы в произвольном порядке: BiIter. Двунаправленного доступа - сохраняет и извлекает элементы допускает перемещение вперед и назад. ForIter. Прямой - сохраняет и извлекает элементы, перемещение вперед. InIter. Входной – извлекает (но не сохраняет) значения, перемещение вперед. OutInter. Выходной – сохраняет, но не извлекает значения, перемещение вперед. RanIter. Итератор с большими возможностями можно применять вместо итератора с меньшими возможностями. Для итераторов поддерживаются операции с указателями, допустимыми для категории итератора: Так, входной итератор должен поддерживать операции: ->, ++, *, ==, != Для выходного итератора и произвольного доступа: ->, ++, *, ==, !=, --, <, .>,>=, <=, +=, [] 11.6 Аллокатор Аллокатор – объект, который выделяет контейнеру память. Для каждого контейнера STL создан собственный аллокатор. Можно определять свои аллокаторы, если это нужно специализированному приложению. 11.7 Функциональные объекты Функциональные объекты – это экземпляры классов, определяющих operator(). В STL определены Ф.О.: less() – больше ли один объект другого;plus(); minus(); multiplies(); divides(). 11.8 Общая функциональность контейнера • Поддержка присваивания • Поддерживать операции сравнения • Должны иметь конструктор по умолчанию (создание пустого контейнера) и копирующий конструктор. • Должен иметь деструктор, освобождающий память из под контейнера и вызывать деструктор уничтожения каждого элемента в контейнере. • Должен предоставлять итераторы. Это гарантирует, что ко всем контейнерам можно применять алгоритмы. • Все контейнера должны предоставлять функции: iterator begin() – итератор на 1 элемент const iterator begin() - константный итератор на 1 элемент iterator end() - итератор на последний элемент const iterator end() – size_type max_size() const - максимально возможное количество элементов size_type size() const – количество элементов в контейнере void swap (тип контейнера С) – обмен двух контейнеров Обратный итератор – это итератор, поддерживающий двунаправленный доступ . Содержит: revers_iterator rbegin() – на последний элемент revers_iterator rend() – на позицию, предшествующую первому элементу. 11.9 Функции последовательных контейнеров: void clear() –удаление элементов из контейнера iterator erase(iterator i) – удаление элемента в позиции i. iterator erase(iterator start, iterator end) - удаление элементов от start до end iterator insert(iterator I, const T&val) – вставляет val в позицию I контейнера. И др.функции. 11.10 Функции ассоциативных контейнеров void clear() pair Если не найден, то на конец контейнера. iterator insert(const key_type &K) – key_compare key_comp() const – возвращает функциональный объект, сравнивающий два ключа. Пример. Применение базовых операций к последовательному контейнеру на основе вектора (vector). Создать контейнер Добавить элемент в контейнер Определить размер контейнера Использовать итератор для прохода по контейнеру Присвоить один контейнер другому Определить эквивалентность двух контейнеров Удалить элементы из контейнера Менять элементы контейнера Проверить контейнер на пустоту #include "stdafx.h" #include #include void show( const char *msg, vector< char > vect){ vector< char >::iterator itr; cout< " " ; cout<< '\n' ; } int _tmain( int argc, _TCHAR* argv[]) { //объявление пустого конт vector< char > v; //объявление итератора для vector char >::iterator itr; //получить итератор на начало itr=v.begin(); //вставка символов в v. результат - итератор на вставляемый объект itr=v.insert(itr, 'A' ); itr=v.insert(itr, 'B' ); v.insert(itr, 'C' ); //отобразить содержимое v show("Содержимое v:",v); //объявление обратного итератора vector< char >::reverse_iterator ritr; //отобразить v в обратном порядке, используя обратный итератор for (ritr=v.rbegin();ritr!=v.rend();++ritr) cout<<*ritr<< ' ' ; cout<< "\n\n" ; //создать другой вектор, идентичный первому vector< char > v2(v); show("Содержимое v2:",v2); cout<< "\n\n" ; //размер v cout<< "размер v=" < ; //сравнить два контейнера if (v==v2) cout<< "Эквивалентны" << "\n\n" ; //вставит символы в конец контейнеров v и v2 v.insert(v.end(), 'D' ); v2.insert(v2.end(), 'E' ); v2.insert(v2.end(), 'X' ); show("Содержимое v:",v); show("Содержимое v2:",v2); //сравнить v ; //вставим Z в начало v v.insert(v.begin(), 'Z' ); show("Содержимое v:",v); //удалить первый элемент из v2 v2.erase(v2.begin()); show("Содержимое v2:",v2); cout<< "\n\n" ; //очистить v v.clear(); if (v.empty()) cout<< "Теперь пуст" << "\n\n" ; cin.get(); cin.get(); return 0; } Пример разработки шаблона – контейнер множество. Предусмотрев операции: • включить элемент в множество • входит ли элемент в множество • возвращает элемент множества • размер множества • пусто ли множество • объединение двух множеств • пересечение двух множеств • дополнение двух множеств • вывод множества • заполнение множества • Тестирвание шаблона на типах: int, char, класс Book • Определение и реализация шаблонного класса в одном файле заголовка Мoдуль class_Set class Set { private: T *x; int n; public: Set(){n=0;x=0;} Set( int n1){n=n1;x= new T[n];} // in-line Set(){ delete []x;} void push_back(T a); //включитьэлемент в множество bool in(T a); //входит ли элемент в множество T operator[](int i); //возвращает элемент int size(); bool Empty(); //пусто ли мнжество //объединение двух множеств Set //пересечение двух множеств Set //дополнение множества Set //friend ostream& operator<<(ostream &os,Set Realloc(); friend ostream& operator <<(ostream &os,Set { for ( int i=0;i ; os< }; #include "stdafx.h" #pragma once #include { private: T *x; int n; public: Set(){n=0;x=0;} Set( int n1){n=n1;x= new T[n];} // in-line Set(){ delete []x;} void push_back(T a); //включитьэлемент в множество bool in(T a); //входит ли элемент в множество bool Empty(); //пусто ли мнжество //объединение двух множеств Set //пересечение двух множеств Set //дополнение множествак Set <<(ostream &os,Set { for ( int i=0;i ; os< }; //включитьэлемент в множество template Set (n==0) {x= new T[1];x[n]=a;n++;} else{ if (!( this ->in(a))) x=(T*) realloc(x, sizeof (T)*(n+1)); x[n]=a;n++; } } //пусто ли мнжество template Set { return x==0; } //входит ли элемент в множество template Set { int i=0; while (i< this ->n && x[i]!=a) { i++; } return (i< this ->n); } //объединение двух множеств template Set { int i; n=S1.n; this ->x= new T[n]; for (i=0;i this ->in(S2.x[i]))) this ->push_back(S2.x[i]); return *this; } //пересечение двух множеств template Set { int i,j; for (i=0;i for (j=0;j if ((S1.in(S2.x[j]))&&(!( this ->in(S1.x[j])))) this ->push_back(S2.x[j]); }} return *this; } //дополнение множествак template Set { int i,j; for (i=0;i (j=0;j (!(S2.in(S1.x[i])) &&(!( this - >in(S1.x[i])))) this ->push_back(S1.x[i]); } } return *this; } Модуль Book.h #pragma once #include using namespace std; class Book {private: string ISBN; //ключ string author; string Title; unsigned int year_published; string pablished; public: Book(void){ISBN="";author="";Title="";year_published=0;pablished="";} Book(string ISBN1,string aut, string T, unsigned int year, string pub); bool operator !=(Book &B); friend ostream& operator <<(ostream &os,Book &O); friend istream& operator >>(istream &is,Book &O); }; Модуль Book.cpp #include "StdAfx.h" #include "Book.h" Book::Book(string ISBN1,string aut,string T, unsigned int year,string pub) { ISBN=ISBN1;author=aut;Title=T;year_published= year; pablished=pub; } bool Book:: operator !=(Book &B) { return (ISBN!=B.ISBN); } ostream& operator <<(ostream &os,Book O) { os< ' < ' < ' < < >>(istream &is,Book &O) { is>>O.ISBN; is>>O.author; is>>O.Title; is>>O.year_published; is>>O.pablished; return is; } Основная прграмма // MySet_template.cpp: определяет точку входа для консольного приложения. // #include "stdafx.h" #include "class_set.h" #include "Book.h" #include void find_glasn(); int _tmain( int argc, _TCHAR* argv[]) { Set< int > S; S.push_back(2); S.push_back(3); S.push_back(4); Set< int > S1; S1.push_back(2); S1.push_back(5); S1.push_back(4); Set< int > S2; //S2.union_m(S,S1); //S2.intersect(S,S1); S2.acsept(S,S1); cout< Book B1("111","Shild","C++",2017,"Dialog"); Book B2("110","Shild","C#",2017,"Dialog"); SB.push_back(B1); SB.push_back(B2); cout< { //множество гласных букв string s= "аеиоуэюя" ; Set< char > glasnAll, glasnWord, S3; for ( int i=0;i< int (s.size());i++) glasnAll.push_back(s[i]); //множество гласных букв слова Програмирование s="Программирование"; int n=s.size(); for ( int i=0;i (glasnAll.in(x)) |