Справочник от Автор24
Поделись лекцией за скидку на Автор24

Шаблоны (templates). Обобщенное программирование (Generics)

  • 👀 290 просмотров
  • 📌 242 загрузки
Выбери формат для чтения
Загружаем конспект в формате doc
Это займет всего пару минут! А пока ты можешь прочитать работу в формате Word 👇
Конспект лекции по дисциплине «Шаблоны (templates). Обобщенное программирование (Generics)» doc
Шаблоны (templates). Обобщенное программирование(Generics) . 1) Шаблоны функций (template) на C++ Шаблоны предназначены для повторного использования кода (reuse) в различных классах. Имеется фрагмент кода, который в проекте последовательно применяется к различным типам данных. Пример. Обмен значений переменных (int float, char, объекты класса) a, b void Change(int &a,int &b) { c=a; a=b; b=c; } Для char можно сделать перегрузку: void Change(char &a,char &b) { c=a; a=b; b=c; } Код у этих функций одинаковый! Для общей функции обмена используется шаблон функции, при вызове компилятор меняет параметр на конкретный тип. #include "stdafx.h" class Record { private: int min,sec; public: void Init(int m,int s); }; void Record::Init(int m,int s) { min=m; sec=s; } template // шаблон с одним параметром T void Change(T &a,T &b) // Функция с шаблоном T { T c; c=a; a=b; b=c; } int _tmain(int argc, _TCHAR* argv[]) { int a=5,b=3; double c=6.0,d=8.0; Change(a,b); // вызов с целыми аргументами Change(c,d); // вызов с вещественными аргументами Record x; Record y; x.Init(3,5); y.Init(5,3); Change(x,y); // с аргументами объектами Record return 0; } В проекте имеются 2 независимых класса Record и Angle, у которых имеются поля с одинаковыми названиями min, sec. Функция округления до минут представляет собой шаблон. #include "stdafx.h" class Record { private: int min,sec; public: Record(int m,int s); int Getmin(); int Getsec(); }; Record::Record(int m,int s) { min=m; sec=s; } int Record::Getmin() { return min; } int Record::Getsec() { return sec; } class Angle { private: int grad,min,sec; public: Angle(int g,int m,int s); int Getmin(); int Getsec(); }; Angle::Angle(int g,int m,int s) { grad=g; min=m; sec=s; } int Angle::Getmin() { return min; } int Angle::Getsec() { return sec; } template int Roundmin(T &a) // шаблон функции { if(a.Getsec()>=30) return a.Getmin()+1; else return a.Getmin(); } int _tmain(int argc, _TCHAR* argv[]) { Record r(3,50); Angle a(3,4,34); int m,n; m=Roundmin(r); // m=4 n=Roundmin(a); // n=5 return 0; } 2) Шаблоны классов на C++ Шаблон - массив с методами ввода и вычисления суммы элементов массива. Для Record необходима перегрузка операторов. #include "stdafx.h" #include using namespace std; class Record { private: int min,sec; Record operator+(Record b); // перегрузка сложения Record+Record }; Record operator >> (istream &o,Record &r) { cin >> r.min >> r.sec; return r; } Record Record::operator+(Record b) { Record c; c.min=this->min+b.min; c.sec=this->sec+b.sec; if(c.sec>=60) { c.min++; c.sec -= 60; } return c; } template class Array // общий класс Array для типа данных T { public: Array(int s); // конструктор с параметром void Read(); // ввод элементов массива T sum(); // сумма элементов массива типа T, результат тип T private: T *data; // массив данных int size; // размер массива }; template Array:: Array(int s) // конструктор { data=new T[s]; size=s; } template void Array::Read() { int i; for(i=0;i> data[i]; // cin>> должна быть определена! } } template T Array::sum() { T a; int i; a=data[0]; for(i=1;i Z(5); // массив целых чисел int s; Z.Read(); s=Z.sum(); Array Y(4); // массив вещественных чисел double p; Y.Read(); p=Y.sum(); Array X(3); // массив объектов Record Record R; X.Read(); R=X.sum(); // сумма элементов Record return 0; } 3) Обобщенные методы и классы (generics) на Java Обычный метод Change в Java из-за ссылок не работает. В С++ метод обмена Record: public static void Change(Record &a,Record &b) { Record c; c=a; a=b; b=c; } Аналог в Java: public static void Change(Record a,Record b) { Record c; c=a; a=b; b=c; } public static void main (String args[] ) { Record s=new Record(1,2); Record q=new Record(2,1); Record.Change(s, q); // s: min=1 sec=2 q: min=2 sec=1 остались прежними } Без метода обмен в коде совершается. public static void main (String args[] ) { Record s=new Record(1,2); Record q=new Record(2,1); Record w; w=s; s=q; q=w; // s: min=2 sec=1 q: min=1 sec=2 } Вариант Change обмена по полям. public static void Change(Record a,Record b) { int m,s; m=a.min; s=a.sec; a.min=b.min; a.sec=b.sec; b.min=m; b.sec=s; } Обобщенный метод обмена значениями не работает. public class lab8 { public static void Change(T a,T b) // - параметр метода, заменяемый конкретным типом { T c; c=a; // обмен локальными ссылками a=b; b=c; } ...... } public static void main (String args[] ) { int a=5,b=3; Change(a,b); // те же значения Record s=new Record(1,2); Record q=new Record(2,1); Change(s,q); // те же значения } Обобщенный метод перестановки элементов массива в обратном порядке. public class lab8 { public static void Reverse(T[] x) // x – массив обобщенного типа T { T temp; int i; int k; k=x.length; for(i=0;i<=k/2;i++) { temp=x[i]; x[i]=x[k-i-1]; x[k-i-1]=temp; } } public static void main (String args[] ) { Integer nums[]={1,2,3,4}; Record r=new Record[5]; Reverse(nums); // 4 3 2 1 for(i=0;i<5;i++) { r[i]=new Record(i,1); } Reverse(r); // {4 1} {3 1} {2 1} {1 1} {0 1} } } Аналог варианта C++ Roundmin приводит к ошибке компиляции. public static int Roundmin(T a) { if(a.Getsec()>=30) // a не содержит метода Getsec() ! a – объект класса Object return a.Getmin()+1; else return a.Getmin(); } После запуска программы информация о реальном типе, который замещает T отсутствует! Можно использовать аргументы ограниченного типа (bounded type). class Record { protected int min,sec; public Record(int m,int s) { min=m; sec=s; } public int Getsec() { return sec; } } class Sprint extends Record { private int dec; Sprint(int m,int s,int d) { super(m,s); dec=d; } } public class lab8 { ..... public static int Roundmin(T a) // обобщенный метод для класса Record и всех его производных, например, Sprint { if(a.Getsec()>=30) return a.Getmin()+1; else return a.Getmin(); } ...... public static void main (String args[] ) { Record v=new Record(2,40); Sprint z=new Sprint(3,35,2); int m,n; m=Roundmin(v); n=Roundmin(z); } Пример обобщенного класса массива общего типа на Java Аналог класса обобщенного массива для C++ создать не удается. Array содержит конструктор и метод суммы элементов. class Array // класс с параметром { private T[] ob; private int size; Array(T[]o) { ob=o; } T sum() { int i; T a; a=ob[0]; for(i=1;i Z=new Array(num); // создан массив из целых чисел Record r=new Record[5]; for(i=0;i<5;i++) { r[i]=new Record(i,1); } Array X=new Array (r); // создан массив из объектов Record Для массивов типа Record и производных создается обобщенный класс с ограниченным типом. В Record добавлен метод Add позволяющий складывать 2 Record и производные от него. class Record { protected int min,sec; public Record(int m,int s) { min=m; sec=s; } public int Getmin() { return min; } public int Getsec() { return sec; } public static void Ch(Record a,Record b) { Record c=new Record(0,0); c=a; a=b; b=c; } public Record Add(Record a,Record b) // добавлен метод сложения двух объектов { Record c=new Record(0,0); c.min=a.min+b.min; c.sec=a.sec+b.sec; if(c.sec>=60) { c.min++; c.sec-=60; } return c; } } class Sprint extends Record { private int dec; Sprint(int m,int s,int d) { super(m,s); dec=d; } } class Array // параметр T только для Record и подклассов, например, Sprint { private T[] ob; private int size; public Array(T[]o) { ob=o; } T sum() { int i; T a; a=ob[0]; for(i=1;i X=new Array (r); Sprint u=new Sprint[4]; for(i=0;i<4;i++) { u[i]=new Sprint(1,i,3); } Array X=new Array (r); Array Y=new Array (u); // массив объектов из Sprint Record s=new Record(0,0); Record t=new Record(0,0); s=X.sum(); // s: min=10 sec=5 t=Y.sum(); // t: min=4 sec=6 } 3) Обобщенные методы и классы (generics) на C# Пример. Обмен значений переменных (int float, char, объекты класса) a, b аналогично C++. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Record { private int min, sec; public void Init(int m, int s) { min = m; sec = s; } } class Program { static void Change(ref T a, ref T b) // метод с параметром { T c; c = a; a = b; b = c; } static void Main(string[] args) { int a = 5, b = 3; double c = 6.0, d = 8.0; Change(ref a, ref b); // вызов с целыми аргументами Change(ref c, ref d); // вызов с вещественными аргументами Record x=new Record(); Record y=new Record(); x.Init(3, 5); y.Init(5, 3); Change(ref x, ref y); // с аргументами объектами Record } } } В проекте имеются класс Record и прозводный класс Sprint. Функция округления до минут представляет собой шаблон с ограничениями на параметры. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Record { private int min, sec; public Record(int m, int s) { min = m; sec = s; } public int Getmin() { return min; } public int Getsec() { return sec; } } class Sprint : Record { private int dec; public Sprint(int m, int s, int d) : base(m, s) { dec = d; } } class Program { static int Roundmin(T a) where T:Record // параметр T тип Record или производные классы { if (a.Getsec() >= 30) return a.Getmin() + 1; else return a.Getmin(); } static void Main(string[] args) { Record r=new Record(3,40); Sprint s = new Sprint(5, 45, 50); int m,n; m = Roundmin(r); n = Roundmin(s); } } } Пример обобщенного класса массива общего типа на C# Аналог класса обобщенного массива для C++ создать не удается. Array содержит конструктор и метод суммы элементов. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Record { private int min, sec; public Record(int m, int s) { min = m; sec = s; } public int Getmin() { return min; } public int Getsec() { return sec; } public Record Add(Record a, Record b) // добавлен метод сложения двух объектов { Record c = new Record(0, 0); c.min = a.min + b.min; c.sec = a.sec + b.sec; if (c.sec >= 60) { c.min++; c.sec -= 60; } return c; } } class Sprint : Record { private int dec; public Sprint(int m, int s, int d) : base(m, s) { dec = d; } } class Array where T:Record { private T[] ob; private int size; public Array(T[] o) { ob = o; } public T sum() { int i; T a; a = ob[0]; for (i = 1; i < ob.Length; i++) { a = (T)a.Add(a, ob[i]); } return a; } } static void Main(string[] args) { Record []rec=new Record[5]; int i; for(i=0;i<5;i++) { rec[i]=new Record(i,1); } Sprint[] sp = new Sprint[4]; for (i = 0; i < 4; i++) { sp[i] = new Sprint(1, i,4); } Array X = new Array(rec); Array Y = new Array(sp); Record f=new Record(0,0); Record t=new Record(0,0); f=X.sum(); // s: min=10 sec=5 .... 4) Делегаты на C# Делегат – объект для вызовов методов с одинаковыми аргументами и возвращаемым типом (одинаковой сигнатурой). Пример. В проекте калькулятор целых чисел имеется ряд вычислительных методов, у всех 2 аргумента целого типа и они возвращают целое число. Объявлен делегат для работы с указанными методами. using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace ConsoleApplication1 { class Program { static int Add(int a, int b) { return a + b; } static int Sub(int a, int b) { return a - b; } static int Mult(int a, int b) { return a * b; } static int Div(int a, int b) { return a / b; } public delegate int Calc(int a, int b); // делегат Calc для вычислений static void Main(string[] args) { Calc A = Add; // A экземпляр делегата для сложения int Result; Result = A(4, 6); // вызов метода сложения Result=10 Calc S = Sub; // B экземпляр делегата для вычитания Result = S(6, 2); // вызов метода сложения Result=14 A = Mult; // теперь A для умножения Result = A(3, 5); // вызов метода умножения Result=15 S = Add; S+=Mult; // операции над делегатами S-=Mult; } } } 5) Виртуальный деструктор и виртуальное наследование в C++ Если класс полиморфен, желательно деструктор объявлять виртуальным. Если нет, возможна некорректная очистка памяти. class Record { ~Record(); // простой деструктор .............. }; class Sprint:public Record { ~Sprint(); ..... }; метод: void F(Record *a) { ....... delete a; } Пусть указатель a указывает на производный класс, но вызовется только деструктор базового класса. виртуальный деструктор ккак положено, сначала производного класса, потом базового. Пример множественного наследования. Пусть в классе Record имеется поле weight – вес, который поднял штангист и такое же поле в классе Person – собственный вес человека. class Record { public: int weight; // вес штанги ....... } class Person { public: char Fam[30]; int Vozrast; int weight; // вес спортсмена ...... } class Sportsman : public Person , public Record // наследуются оба веса { public: void Putweight(int x); private: int Category; // разряд спортсмена ............ } Создаем класс Gravity с полем weight (вес). class Gravity { protected: int weight; ......... }; Record и Person наследуются от Gravity class Record:public Gravity { protected: int min,sec; ....... } class Person:public Gravity { protected: char Fam[30]; int Vozrast; ...... } Теперь Sportsman наследуется от Person и Record class Sportsman : public Person , public Record { public: void Putweight(int x); private: int Category; ............ } В памяти Sportsman сначала идут поля и методы Person, потом Record, потом собственные. Поэтому в Sportsman 2 поля weight!! Проблему решает виртуальное наследование. class Record:virtual public Gravity { protected: int min,sec; ....... } class Person:virtual public Gravity { protected: char Fam[30]; int Vozrast; ...... } В Sportsman одна копия weight.
«Шаблоны (templates). Обобщенное программирование (Generics)» 👇
Готовые курсовые работы и рефераты
Купить от 250 ₽
Решение задач от ИИ за 2 минуты
Решить задачу
Помощь с рефератом от нейросети
Написать ИИ

Тебе могут подойти лекции

Смотреть все 588 лекций
Все самое важное и интересное в Telegram

Все сервисы Справочника в твоем телефоне! Просто напиши Боту, что ты ищешь и он быстро найдет нужную статью, лекцию или пособие для тебя!

Перейти в Telegram Bot