'

Задачи на 28 апреля

Понравилась презентация – покажи это...





Слайд 0

Задачи на 28 апреля Язык С++ 1


Слайд 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


Слайд 2

Задача 1: Удаление кружка - план OnRButtonDown Ищем кружок, в который мы попали Если нашли, то удаляем Перерисовываем Язык С++ 3


Слайд 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


Слайд 4

Архитектура "Документ/представление" (Document-View) Язык С++ 5


Слайд 5

Тут мы обсуждали, почему лучше иметь два класса – один для данных, и другой для их изображения


Слайд 6

Архитектура Document-View Данные хранятся не в окне, а в отдельном классе (C…Doc, производный от CDocument) Взаимодействие: Из окна можно получить указатель на документ: pDoc = GetDocument(); Можно обновить окно для документа (или окна, их может быть несколько): UpdateAllViews(NULL); Почему удобно использовать такую архитектуру? Несколько окон для одного документа Несколько способов просмотра Вообще часто полезно разделять объект и его изображение Примерно то же: MVC (model-view-controler). Язык С++ 7


Слайд 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


Слайд 8

Шаблоны классов Язык С++ 9


Слайд 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


Слайд 10

Замечания Методы можно описывать вне класса template <class T> void stack<T>::push(const T& x) { ... } В частности, конструктор: template <class T> stack<T>::stack(): size(0) {} Язык С++ 11


Слайд 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


Слайд 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


Слайд 13

typename - продолжение template <class T> void f(T x) { … typename T::mytype y; … } typename относится к выражению T::mytype Означает: "мы обещаем, что при вызове это будет вложенный в T тип" Язык С++ 14


Слайд 14

Специализация Специализация шаблона template <> class stack<char*> { // Что-то особенное }; Специализация метода template <> void stack<double>:: push(double x) { // Что-то особенное }; Реальный пример из STL – vector<bool> Язык С++ 15


Слайд 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


Слайд 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


Слайд 17

Параметры - шаблоны Не будет на экзамене template < template<class > class T > class abc { T<int> x; T<double> y; T<double> z; … }; abc<stack> v; Язык С++ 18


Слайд 18

Замечания Пишем код, который работает для разных типов. Называется: полиморфизм Статический полиморфизм По-моему опыту: Не старайтесь использовать сложные возможности шаблонов Легко запутаться Язык С++ 19


Слайд 19

Еще об итераторах и контейнерах


Слайд 20

value_type T::value_type – тип того, что содержится в контейнере Например, если T – это list<int>, то T::value_type – это int И тоже для итераторов Если T – это list<int>::iterator, то T::value_type – это int Используется, в основном, в шаблонах Тут мы разбирали простой пример использования: шаблон функции, которая возвращает первый элемент любого последовательного контейнера. И обсудили типичные ошибки.


Слайд 21

Разделяемые данные (В частности, разделяемая память и когда ее удалять) Язык С++ 22


Слайд 22

Несколько указателей на один объект в динамической памяти Вспомним проблемы при копировании string: Меняем одну строку – меняются все Ну, допустим, мы не меняем строки (immutable objects) Оставшиеся проблемы одним предложением: “непонятно, когда удалять” Один из вариантов решения – счетчик указателей При объекте храним количество указателей, которые на него указывают Тогда можем сказать, когда можно удалить (когда счетчик уменьшился до 0) Язык С++ 23


Слайд 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


Слайд 24

Программы из нескольких исходных файлов Язык С++ 25


Слайд 25

Программа из нескольких файлов -1 Схема a.cpp b.cpp ? компилируем... а.obj b.obj ? linker … a.exe (или a.dll) Как определить что-то в одном файле, а использовать в другом? a.cpp void f(int i) { … } b.cpp … f(56); … // f надо объявить


Слайд 26

Программа из нескольких файлов -2 a.cpp void f(int i) { … } b.cpp void f(int i); ... … f(56); … // ОК, так все работает, но: // обычно так не делают! Почему? Неудобно, особенно если файлов много При изменениях надо много где исправлять Легко забыть исправить.


Слайд 27

Программа из нескольких файлов – обычно пишут так: Директива 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 (все необходимые объявления)


Слайд 28

Как добавить в проект новые файлы? Пусть мы хотим добавить в проект новый cpp файл. В Visual Studio это делается так: В меню выберите Project + Add New Item… В форме выберите в списке «С++ File (.cpp)» и в поле Name введите имя файла. Чтобы добавить новый h файл надо сделать то же самое, но в списке выбрать «Header File (.h)» Если не будет получаться – пишите, я подскажу.


Слайд 29

Задачи на 5 мая Язык С++ 30


Слайд 30

Задачи на 5 мая - 1 «Разные фигурки» Написать программу типа Circles, которая позволяет задавать картинки из каких-нибудь трех видов фигур (например, кружки, квадраты и ромбы). Д.б. возможность добавлять и удалять. Перемещение можно не реализовывать. Как выбирать фигуру для добавления? Один вариант: в меню выбираeм "текущую фигуру". О работе с меню будет документ на сайте. За эту задачу 2 балла – один за добавление и один за удаление. Опишите шаблон функции, которая для любого последовательного контейнера (списка, вектора, deque) ищет сумму входящих в него положительных элементов. Замечание: шаблон должен работать не только для контейнеров из целых чисел, но и для вещественных, rational и т.д. (Продолжение на следующем слайде) Язык С++ 31


Слайд 31

Задачи на 5 мая – 2 Шаблон 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. При этом строчки не должны никогда реально копироваться. Надо только переставлять указатели, подсчитывать их количество, и удалять строки, на которые уже никто не указывает. За эту задачу тоже можно заработать два балла. Один балл для тех, кто напишет что-то похожее на правильное решение, и второй балл за совсем правильное решение. (Окончание на следующем слайде) Язык С++ 32


Слайд 32

Задачи на 5 мая – 3 Написать функцию, которая для целого числа проверяет, совершенное оно или нет, и возвращает true или false. Справка: число называется совершенным, если оно равно сумме своих делителей. Например: 28 = 1+2+4+7+14 Что для такой функции д.б. написано в cpp файле, и что в h файле? Дополнительное пожелание: Желательно, чтобы функция работала по возможности быстро.


×

HTML:





Ссылка: