330 likes | 474 Views
Задачи на 28 апреля. Язык С++. 1. Задача 3: swp. template <class T> void swp(T& x, T& y) { T tmp = x; x = y; y = tmp; } Замечание: T tmp ; // Так хуже, чем T tmp = x; tmp = x; - Немного медленнее
E N D
Задачи на 28 апреля Язык С++ 1
Задача 3: swp template <class T> void swp(T& x, T& y) { T tmp = x; x = y; y = tmp; } Замечание: T tmp; // Так хуже, чем T tmp = x; tmp = x; - Немного медленнее - Более существенно, работает только если в классе есть конструктор по умолчанию (определение менее общее). Язык С++ 2
Задача 1: Удаление кружка - план OnRButtonDown Ищем кружок, в который мы попали Если нашли, то удаляем Перерисовываем Язык С++ 3
Задача 1: Удаление кружка void CCirclesView::OnRButtonDown(UINT nFlags, CPoint point) { vector<CPoint>::iterator p; for (p=m_circles.begin(); p != m_circles.end(); p++) { if ((p->x - pt.x)*(p->x - pt.x) + (p->y - pt.y)*(p->y - pt.y) <= 100 ) { // Попали в круг? m_circles.erase(p); Invalidate(); break; // Больше не ищем } } CView::OnRButtonDown(nFlags, point); } Перерисовать лучше только если куда-то попали Кстати: тут после erase пользоваться p нельзя! Язык С++ 4
Архитектура "Документ/представление" (Document-View) Язык С++ 5
Тут мы обсуждали, почему лучше иметь два класса – один для данных, и другой для их изображения
Архитектура Document-View • Данные хранятся не в окне, а в отдельном классе (C…Doc, производный от CDocument) • Взаимодействие: • Из окна можно получить указатель на документ: pDoc = GetDocument(); • Можно обновить окно для документа (или окна, их может быть несколько): UpdateAllViews(NULL); • Почему удобно использовать такую архитектуру? • Несколько окон для одного документа • Несколько способов просмотра • Вообще часто полезно разделять объект и его изображение • Примерно то же: MVC(model-view-controler). Язык С++ 7
Circles в архитектуре Document-View • m_circles - перенестив CCirclesDoc class CCirclesDoc { vector<CPoint> m_circles; • OnDraw:CCirclesDoc* pDoc= GetDocument(); for (int i = 0; i < pDoc->m_circles.size(); i++) { CPoint& pt = pDoc->m_circles[i]; pDC->Ellipse(pt.x – 10, pt.y – 10, pt.x + 10, pt.y + 10, } • OnLButtonDown: CCirclesDoc* pDoc= GetDocument(); pDoc->m_circles.push_back(point); pDoc->UpdateAllViews(NULL); Язык С++ 8
Шаблоны классов Язык С++ 9
Пример: шаблон класса "стек" template <class T> class stack { T stk[100]; int size; public: stack() : size(0) {} void push(const T& x) { size[top++] = x; } T pop { return stk[--size]; } }; Использование stack<int> s1; stack<double> s2; stack<complex> s3; stack<stack<int>> s4; При использовании параметры надо указывать явно Язык С++ 10
Замечания Методы можно описывать вне класса template <class T> void stack<T>::push(const T& x) { ...} В частности, конструктор: template <class T> stack<T>::stack(): size(0) {} Язык С++ 11
Не типовые параметры: template <class T,int maxsize> class stack { T stk[maxsize]; … }; stack<int, 100> s; Такие параметры м.б. только целые (и в некоторых случаях указатели) При вызове д.б. константы Внутри - как константы Параметры по умолчаниюtemplate <class T, int maxsize= 100>class stack { … stack<int> s;// To же, что stack<int, 100> Еще возможности Язык С++ 12
typename Пусть в разных классах определен один вложенный тип. class a { typedef int mytype; … }; class b { typedef double mytype; … }; class c { typedef bool mytype; … }; И мы пишем шаблон, в котором используем это. template <classT> void f(T x) { … T::mytype x; … } Проблема: Откуда компилятор знает, что T::mytype это тип (а не поле T или метод T и т.д.)? Приходится подсказывать.. Язык С++ 13
typename - продолжение template <class T> void f(T x) { … typename T::mytype y; … } typename относится к выражению T::mytype Означает: "мы обещаем, что при вызове это будет вложенный в T тип" Язык С++ 14
Специализация Специализация шаблона template <> class stack<char*> { // Что-то особенное }; Специализацияметода template <> void stack<double>:: push(double x) { // Что-то особенное }; Реальный пример из STL – vector<bool> Язык С++ 15
Частичная специализация template <class T> class stack<T*> { // Что-то особенное }; М.б. сложная система разных специализаций template <class T1, class T2> class abc { … }; template <class T> class abc<T, T> { … }; template <class T> class abc<T, int> { … }; template <class T> class abc<T*, T> { … }; template <class T1, class T2> class abc<T1*, T2*> { … }; Не во всех компиляторах! (Visual C++ после VS 2003) Язык С++ 16
Шаблон метода class abc { … template <class T> void f(T x) { … } … }; abc x; x.f(5); // f<int> x.f(3.14); // f<double> // Пример template <class T> class complex { T re, im; … template <class T1> complex(const T1& from) : re(from.re), im(from.im) {} }; // Хотим задать преобразование // complex -> complex complex<int> c1(1,2); complex<double> c2 = c1; Генерируется конструктор complex<double> (const complex<int>& from) Язык С++ 17
Параметры - шаблоны Не будет на экзамене template < template<class > class T > class abc { T<int> x; T<double> y; T<double> z; … }; abc<stack> v; Язык С++ 18
Замечания • Пишем код, который работает для разных типов. Называется: полиморфизм • Статический полиморфизм • По-моему опыту: Не старайтесь использовать сложные возможности шаблонов • Легко запутаться Язык С++ 19
value_type • T::value_type – тип того, что содержится в контейнере Например, если T – это list<int>, то T::value_type – это int • И тоже для итераторов Если T – это list<int>::iterator, то T::value_type – это int • Используется, в основном, в шаблонах • Тут мы разбирали простой пример использования: шаблон функции, которая возвращает первый элемент любого последовательного контейнера. И обсудили типичные ошибки.
Разделяемые данные (В частности, разделяемая память и когда ее удалять) Язык С++ 22
Несколько указателей на один объект в динамической памяти Вспомним проблемы при копировании string: • Меняем одну строку – меняются все • Ну, допустим, мы не меняем строки (immutable objects) • Оставшиеся проблемы одним предложением: “непонятно, когда удалять” • Один из вариантов решения – счетчик указателей • При объекте храним количество указателей, которые на него указывают • Тогда можем сказать, когда можно удалить (когда счетчик уменьшился до 0) Язык С++ 23
Строки с разделяемым содержимым // Пример: shared_string s1 = “abc”; shared_string s2 = “klm”; s2 = s1; // “klm” освобождается. На “abc” – 2 указателя. shared_string s3 = “pqr”; s1 = s3; // На “abc” – 1указатель. s2 = s3; // “abc” удаляется • Где хранить счетчик? • Мы не можем хранить в классе shared_string, его тоже надо разделять для нескольких shared_string • Вариант (м.б. не лучший) – в первом байте строки. Но возможны и другие решения Язык С++ 24
Программы из нескольких исходных файлов Язык С++ 25
Схема a.cpp b.cpp компилируем... а.obj b.obj linker … a.exe (или a.dll) Как определить что-то в одном файле, а использовать в другом? a.cpp void f(int i) { … } b.cpp … f(56); … // f надо объявить Программа из нескольких файлов -1
a.cpp void f(int i) { … } b.cpp void f(int i);... … f(56); … // ОК, так все работает, но: // обычно так не делают! Почему? Неудобно, особенно если файлов много При изменениях надо много где исправлять Легко забыть исправить. Программа из нескольких файлов -2
Директива include:#include <имя_файла> смысл: включить в это место текст из файла a.cpp void f(int i) { … } a.h void f(int i); b.cpp #include “a.h” ... … f(56); … с.cpp #include “a.h” ... … f(42); … В a.h – все, что другие должны знать о a.cpp (все необходимые объявления) Программа из нескольких файлов – обычно пишут так:
Как добавить в проект новые файлы? • Пусть мы хотим добавить в проект новый cpp файл. В Visual Studio это делается так: • В меню выберите Project + Add New Item… • В форме выберите в списке «С++ File (.cpp)»и в поле Name введите имя файла. • Чтобы добавить новый h файл надо сделать то же самое, но в списке выбрать «Header File (.h)» • Еслине будет получаться – пишите, я подскажу.
Задачи на 5 мая Язык С++ 30
Задачи на 5 мая - 1 • «Разные фигурки» Написать программу типа Circles, которая позволяет задавать картинки из каких-нибудь трех видов фигур (например, кружки, квадраты и ромбы). • Д.б. возможность добавлять и удалять. Перемещение можно не реализовывать. • Как выбирать фигуру для добавления? Один вариант: в меню выбираeм "текущую фигуру". О работе с меню будет документ на сайте. • За эту задачу 2 балла – один за добавление и один за удаление. Опишите шаблон функции, которая для любого последовательного контейнера (списка, вектора, deque) ищет сумму входящих в него положительных элементов.Замечание: шаблон должен работать не только для контейнеров из целых чисел, но и для вещественных, rational и т.д. (Продолжение на следующем слайде) Язык С++ 31
Шаблон fixed_queue - очередь фиксированной длины (аналог stack, но first in – first out). // Пример использованмя queue<int, 100> q; q.push(3); q.push(7); q.push(11); cout << q.pop(); // 3 cout << q.pop(); // 7 Реализовать shared_string Надо реализовать: конструктор деструктор, оператор=, конструктор копирования, метод print. При этом строчки не должны никогда реально копироваться. Надо только переставлять указатели, подсчитывать их количество, и удалять строки, на которые уже никто не указывает. За эту задачу тоже можно заработать два балла. Один балл для тех, кто напишет что-то похожее на правильное решение, и второй балл за совсем правильное решение. (Окончание на следующем слайде) Задачи на 5 мая – 2 Язык С++ 32
Написать функцию, которая для целого числа проверяет, совершенное оно или нет, и возвращает true или false. Справка: число называется совершенным, если оно равно сумме своих делителей. Например: 28 = 1+2+4+7+14 Что для такой функции д.б. написано в cpp файле, и что в h файле? Дополнительное пожелание: Желательно, чтобы функция работала по возможности быстро. Задачи на 5 мая – 3