МУ_ДЗ_2014 (Методические указания к лабораторным работам), страница 7
Описание файла
Файл "МУ_ДЗ_2014" внутри архива находится в папке "Методические указания к лабораторным работам". Документ из архива "Методические указания к лабораторным работам", который расположен в категории "". Всё это находится в предмете "программирование на основе классов и шаблонов" из 2 семестр, которые можно найти в файловом архиве МГТУ им. Н.Э.Баумана. Не смотря на прямую связь этого архива с МГТУ им. Н.Э.Баумана, его также можно найти и в других разделах. Архив можно найти в разделе "книги и методические указания", в предмете "программирование на основе классов и шаблонов" в общих файлах.
Онлайн просмотр документа "МУ_ДЗ_2014"
Текст 7 страницы из документа "МУ_ДЗ_2014"
lPrint(l20);
l20.clear( );
cout<< "После очистки l20:" << endl;
В первом фрагменте получим результат:
После копирования l в l20:
l[0] = 5
l[1] = 1
l[2] = 2
После очисткиl20:
Список пуст!
Получить текущую размерность списка можно методом size:
cout << "Число элементов в списке = " << l.size( )<< endl;
Получим результат:
Число элементов в списке = 3
Манипулировать с содержимым списка (вставка, удаление и т.д.) можно с помощью методов (insert, remove, erase, remove_if и др.). Здесь приводиться работоспособный фрагмент программы, а комментарии даны в тексте программы:
// Вставка
iter = l.begin( );
iter++; iter++;
cout<< "Вставка:" << endl;
l.insert( iter, 100 );
lPrint(l);
// Удаление по числу
l.remove( 100 );
cout<< "Удаление по числу 100:" << endl;
lPrint(l);
// Удаление по номеру
l.erase( l.begin( ) ); // Из головы списка
cout<< "Удаление по номеру 0:" << endl;
lPrint(l);
// Удаление по итератору
l.push_back( 20 );
l.push_back( 31 );
cout<< "Перед удалением:" << endl;
lPrint(l);
iter = l.begin( );
iter++; iter++; // Сдвиг на два элемента
l.erase( iter );
cout<< "Удаление по итератору 2 (3-й элемент):" << endl;
// Удаление по условию (предикату)
lPrint(l);
list <int> l2 = l;
cout<< "Удаление четных чисел:" << endl;
cout<< " До удаления:" << endl;
l2.remove_if( is_odd<int>( ) );
cout<< " После удаления:" << endl;
lPrint(l2);
В последнем случае нужно создать специальный класс с булевским оператором шаблонного типа (унарный одноместный предикат - функция ):
template <class T> class is_odd : public std::unary_function<T, bool>
{
public:
bool operator( ) ( T& val )
{
return ( val % 2 ) != 1; } }; // Условие предиката – четное = 0
Это позволяет установить для каждого элемента списка значение условия для его удаления. В нашем случае выполняется проверка на честность параметра элемента, передаваемого в функцию. В задании на ЛР необходимо для своего целого списка объявить шаблонный класс для условия удаления элементов с заданным значением переменной.
Для предыдущего фрагмента удаления четных значений из l2, созданного на основе l, получим:
Удаление четных чисел:
До удаления
l[0] = 1
l[1] = 31
l[2] = 20
После удаления четных
l[0] = 1
l[1] = 31
Сортировка списка выполняется методом sort, при этом может быть указан параметр или не указан. Если параметр не задан, то сортировка выполняется в порядке возрастания ключевой переменной (less). При задании параметра сортировки greater сортировка выполняется в порядке убывания основной переменной списка. Примеры и результат приведены ниже.
// Сортировка
l.sort( ); // Сортировка по возрастанию по-умолчанию less
cout<< "После сортировки списка!" << endl;
lPrint(l);
l.sort( greater<int>( ) ); // Сортировка по убыванию
cout<< "После greater сортировки списка!" << endl;
lPrint(l);
l.sort( less<int>( ) ); // Сортировка по возрастанию
cout<< "После less сортировки списка!" << endl;
lPrint(l);
Переупорядочение списка, изменение порядка на обратный, выполняется методом reverse. Пример:
cout<< "После reverse сортировки списка!" << endl;
l.reverse( );
lPrint(l);
Получим результат:
После сортировки списка!
l[0] = 1
l[1] = 2
l[2] = 20
l[3] = 31
После greater сортировки списка!
l[0] = 31
l[1] = 20
l[2] = 2
l[3] = 1
После less сортировки списка!
l[0] = 1
l[1] = 2
l[2] = 20
l[3] = 31
После reverse сортировки списка!
l[0] = 31
l[1] = 20
l[2] = 2
l[3] = 1
Очистка списка (clear):
l.clear( );
cout<< "После очистки списка!" << endl;
lPrint(l);
Получим результат:
Пустой список!
47 Использование класса list для включения объектов своего класса
В рамках ЛР необходимо продемонстрировать использование методов класса список для объектов собственного класса, который определяется вариантом домашнего задания. Использование собственного класса в качестве содержимого списка ряд особенностей. На примере простого класса Point покажем примеры. Пусть создан простой класс (наследование от класса CObject, здесь не используется, а будет необходимо в последующих примерах):
class Point : CObject {
public:
int x; int y;
// Конструкторы
Point(){ x =0 ; y = 0;};
Point(int a , int b ){ x = a ; y = b;};
// Перегружественная дружественная операция вывода в поток
friend ostream & operator <<( ostream & out , Point & obj );
};
ostream & operator <<( ostream & out , Point & obj )
{
out <<"{ x = " << obj.x <<" y = " << obj.y << " } " <<endl;
return out;
};
Тогда мы можем описать разнообразные списки этих объектов. Ниже приведены примеры вариантов использования конструкторов:
Point P2(51,52); // Описание точки для заполнения конструктором
list <Point> lp; // Пустой список lp0
list <Point> lp1( 3 ); // Список с тремя элементами равными 0
list <Point> lp2( 5, P2 ); // Список из пяти элементов равными P2
list <Point> lp3(lp2); // Список l3 на основе списка l2
list <Point>::iterator lp3_Iter;
lp3_Iter = lp3.begin( );
lp3_Iter++; lp3_Iter++;
list <Point> lp4( lp3.begin( ), lp3_Iter ); // Новый список lp4 на основе первых двух элементов lp3
cout<< "КОНСТРУКТОРЫ: СОБСТВЕННЫЙ КЛАСС!!!" << endl;
lPPrint (lp2);
lPPrint (lp4);
Тогда мы можем описать списки этих объектов и итератор для него:
list<Point> lP; // Пустой список
list<Point>::iterator PIter; // Итератор для списка
Point P1(1,2);
Point P2(51,52);
// Заполнение списка
lP.push_back( P1 );
lP.push_back( P2 );
lP.push_front( *new Point(31 ,32) );
Print_list(lP);
Метод печати списка (Print_list) можно объявить сразу для всех типов объектов в виде шаблона следующего приведенного ниже. Он будет работать для всех списков для объектов, в которых перегружена операция вывода:
// Шаблон функции печати списка list
template <class T> void Print_list(T & l)
{ list<Point>::iterator iter;
int i = 0;
if ( !l.empty() )
{
for( iter = l.begin(); iter != l.end() ; iter++ , i++)
{ cout << "l["<< i << "] = " << *iter ;} }
else
cout << "Список пуст!"<< endl;
cout << endl; };
Все другие методы класса list из STL можно использовать для класса Point. Рассмотрим другие примеры. Метод позволяет assign добавить в новый список элементы из первого списка
list <Point> lp20;
cout<< "Исходный список lP:" << endl;
Print_list(lP);
Print_list(lp20);
lp20.assign( lP.begin( ), --lP.end( ) );
cout<< "После копирования lP в lp20:" << endl;
Print_list(lp20);
lp20.clear( );
cout<< "После очистки lp20:" << endl;
Print_list(lp20);
Получим результат, при копировании всего списка без последнего элемента (--lP.end( )):
Исходный список lP:
l[0] = { x = 31 y = 32 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 51 y = 52 }
Список пуст!
После копирования lP в lp20:
l[0] = { x = 31 y = 32 }
l[1] = { x = 1 y = 2 }
После очистки lp20:
Список пуст!
Манипулировать с содержимым списка (вставка, удаление и т.д.) можно с помощью методов (insert, erase, remove_if и др.):
// Вставка по итератору
PIter = lP.begin( );
PIter++; PIter++;
cout<< "Вставка до:" << endl;
Print_list(lP);
cout<< "Вставка после:" << endl;
lP.insert( PIter, P1 );
Print_list(lP);
// Удаление по итератору
lP.erase( lP.begin() );
cout<< "Удаление по итератору (0, конец):" << endl;
Print_list(lP);
// Простой предикат для удаления х = 20
lP.remove_if( is_X20<Point>( ) ); // Работает!!!
cout<< "После удаления x = 20 списка!" << endl;
Print_list(lP);
Простой унарный предикат (задается в виде булевской унарной функции шаблонного класса) для удаления точек с условием х = 20 выглядит так:
template <class T> class is_X20 : public std::unary_function<T, bool>
{ public:
bool operator( ) ( T& val )
{ return ( val.x = = 20 ); // Возвращается истина, если объект в списке имеет х = 20
} };
В результате выполнения данного фрагмента программы получим:
Вставка до:
l[0] = { x = 31 y = 32 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 51 y = 52 }
Вставка после:
l[0] = { x = 31 y = 32 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 1 y = 2 }
l[3] = { x = 51 y = 52 }
Удаление по итератору (0, конец):
l[0] = { x = 1 y = 2 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 51 y = 52 }
l[0] = { x = 20 y = 32 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 1 y = 2 }
l[3] = { x = 51 y = 52 }
После удаления x = 20 списка!
l[0] = { x = 1 y = 2 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 51 y = 52 }
l[0] = { x = 51 y = 52 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 1 y = 2 }
Функция remove (удалить по объекту) требует описания перегруженной операции равенства, присваивания и явных конструкторов копирования. Например:
Point(const Point & p){ x = p.x ; y = p.y ;};
Point & operator=(const Point & p){ x = p.x ; y = p.y ; return *this;};
friend bool operator==(const Point & p1 , const Point & p2) ;
…
// Перегурузка операции сравнения – равенства для удаления по объекту
bool operator==(const Point & p1 , const Point & p2)
{
return ( (p1.x==p2.x) && (p1.y==p2.y) );
};
Тогда можно выполнить следующий фрагмент текста с функцией remove:
lP.insert( PIter, P2 );
lP.insert( PIter, *new Point(51, 61));
Print_list(lP);
lP.remove( P2 );
cout<< "Удаление по объекту P2 (после):" << endl;
Print_list(lP);
В результате выполнения данного фрагмента программы получим (удаляются точки с координатами <51,52>):
Удаление по объекту P2 (до):
l[0] = { x = 31 y = 32 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 1 y = 2 }
l[3] = { x = 51 y = 52 }
l[4] = { x = 51 y = 61 }
l[5] = { x = 51 y = 52 }
l[6] = { x = 51 y = 61 }
l[7] = { x = 51 y = 52 }
Удаление по объекту P2 (после):
l[0] = { x = 31 y = 32 }
l[1] = { x = 1 y = 2 }
l[2] = { x = 1 y = 2 }
l[3] = { x = 51 y = 61 }
l[4] = { x = 51 y = 61 }
Функция remove_if тоже требует описания унарных предикатов. Пусть мы имеем доступную глобальную переменную:
Point GP(51,52);
Тогда можно описать унарный предикат вида:
// Унарная функция для предикта условного удаления по объекту
template <class T> class is_XA : public std::unary_function<T, bool>
{
public:
bool operator( ) ( T& val )
{
return ( val = = GP ); } // Использование перегруженной операции “= =”