
- •1.2 Философские замечания
- •1.3 Процедурное программирование
- •1.4 Модульное программирование
- •1.5 Абстракция данных
- •1.6 Пределы абстракции данных
- •1.7 Объектно-ориентированное программирование
- •1.8 Концепции объектно-ориентированного программирования
- •1.8.1 Инкапсуляция
- •1.8.2 Полиморфизм
- •1.8.3 Наследование
- •1.10 Несколько полезных советов
- •2.2 Перегрузка функций
- •2.3 Перегрузка операторов
- •2.4 Наследование
- •2.5 Конструкторы и деструкторы
- •2.7 Два новых типа данных
- •Глава 3. Классы и объекты
- •3.1 Параметризованные конструкторы
- •3.2 Дружественные функции
- •3.3 Значения аргументов функции по умолчанию
- •3.3.1 Корректное использование аргументов по умолчанию
- •3.4 Взаимосвязь классов и структур
- •3.5 Связь объединений и классов
- •3.6 Анонимные объединения
- •3.7 Inline-функции
- •3.7.1 Создание inline-функций внутри класса
- •3.8 Передача объектов в функции
- •3.9 Возвращение объектов функциями
- •3.10 Присваивание объектов
- •3.11 Конструктор копирования
- •3.12 Массивы объектов
- •3.12.1 Инициализация массивов объектов
- •3.12.2 Создание инициализированных и неинициализированных массивов
- •3.13 Указатели на объекты
- •3.14 Статические члены класса
- •Глава 4. Перегрузка функций и операторов
- •4.1 Перегрузка конструкторов
- •4.2 Локализация переменных
- •4.3 Локализация создания объектов
- •4.4 Перегрузка функций и неопределенность
- •4.5 Определение адреса перегруженной функции
- •4.6 Указатель this
- •4.7 Перегрузка операторов
- •4.8 Дружественная функция-оператор
- •4.9 Ссылки
- •4.9.1 Параметры-ссылки
- •4.9.2 Передача ссылок на объекты
- •4.9.3 Возврат ссылок
- •4.9.4 Независимые ссылки
- •4.9.5 Использование ссылок для перегрузки унарных операторов
- •4.10 Перегрузка оператора []
- •4.11 Создание функций преобразования типов
- •Глава 5. Наследование, виртуальные функции и полиморфизм
- •5.1 Наследование и спецификаторы доступа
- •5.1.1 Спецификаторы доступа
- •5.1.2 Спецификатор доступа при наследовании базового класса
- •5.1.3 Дополнительная спецификация доступа при наследовании
- •5.2 Конструкторы и деструкторы производных классов
- •5.3 Множественное наследование
- •5.4 Передача параметров в базовый класс
- •5.5 Указатели и ссылки на производные типы
- •5.6 Ссылки на производные классы
- •5.7 Виртуальные функции
- •5.8 Для чего нужны виртуальные функции?
- •5.9 Чисто виртуальные функции и абстрактные типы
- •5.10 Виртуальный базовый класс
- •5.11 Раннее и позднее связывание
- •Глава 6. Подсистема динамического выделения памяти
- •6.1 Введение в обработку исключений
- •6.1.1 Перехват всех исключений
- •6.2 Работа с памятью с помощью new и delete
- •6.3 Размещение объектов
- •6.4 Перегрузка new u delete
- •7.1.1 Потоки
- •7.3 Создание собственных операторов вставки и извлечения
- •7.3.1 Создание операторов вставки
- •7.3.2 Перегрузка операторов извлечения
- •7.4 Форматирование ввода/вывода
- •7.4.1 Форматирование с помощью функций-членов класса ios
- •7.4.2 Использование манипуляторов
- •7.5 Создание собственных функций-манипуляторов
- •7.5.1 Создание манипуляторов без параметров
- •7.5.2 Создание манипуляторов с параметрами
- •7.6 Файловый ввод/вывод
- •7.6.1 Открытие и закрытие файлов
- •7.6.2 Чтение и запись в текстовые файлы
- •7.6.3 Двоичный ввод/вывод
- •7.6.4 Определение конца файла
- •7.6.5 Произвольный доступ
- •Глава 8. Ввод/вывод в массивы
- •8.1 Классы ввода/вывода в массивы
- •8.2 Создание потока вывода
- •8.3 Ввод из массива
- •8.4 Использование функций-членов класса ios
- •8.5 Потоки ввода/вывода в массивы
- •8.6 Произвольный доступ в массив
- •8.7 Использование динамических массивов
- •8.8 Манипуляторы и ввод/вывод в массив
- •8.9 Собственные операторы извлечения и вставки
- •8.10 Форматирование на основе массивов
- •Глава 9. Шаблоны и библиотека stl
- •9.1 Функции-шаблоны
- •9.2 Функции с двумя типами-шаблонами
- •9.3 Ограничения на функции-шаблоны
- •9.4 Классы-шаблоны
- •9.5 Пример с двумя типами-шаблонами
- •9.6 Обзор библиотеки stl
- •9.7 Класс vector
- •9.7 Класс string
- •9.8 Класс list
9.8 Класс list
Класс list представляет собой реализацию класса двусвязного списка в виде шаблона, т.е. list – это двусвязный список, способный хранить данные любого типа. Вообще список – это структура данных, отличающаяся от массива тем, что данные хранятся не в непрерывном участке памяти и что допускается добавление элементов во внутрь и в начало списка, т.е. не только в конец. Рассмотрим пример, в котором объявляется список переменных типа int.
#include <list>
using namespace std;
void main()
{
list<int> l;
}
Здесь объявление list<int> l; создает объект l, имеющий тип “список переменных типа int”.
Класс list имеет много общего с классом vector в плане поддерживаемых операций и имен функций-членов. С объектами-списками также можно работать различными способами. Один из вариантов – заполнение списка некоторыми значениями, добавляя их в конец списка. Такую операцию выполняет функция-член push_back().
#include <list>
#include <iostream.h>
using namespace std;
void main()
{
list<int> l;
l.push_back(1);
if(l.size() != 0) cout << "Last element: " << l.back() << endl;
l.push_back(2);
if(l.size() != 0) cout << "New last element: " << l.back() << endl;
}
Эта программа выводит:
Last element: 1
New last element: 2
В данном примере объявляется объект l – список переменных типа int. Затем в конец списка помещается значение 1 (на самом деле оно становится первым значением), после чего выводится на экран. Функция-член size() возвращает число элементов списка и используется здесь для проверки успешности добавления в список нового элемента. Функция-член back() возвращает ссылку на последний элемент списка (в данном случае это все та же 1).
После этого в конец списка добавляется элемент 2 и ситуация повторяется.
Структура данных список не требует перевыделений памяти, поэтому при работе с list можно смело использовать функцию-член push_back(), если это необходимо. По той же причине в классе list отсутствуют функции reserve() и capacity(), которые имелись в классе vector.
При работе со списком необходимо каким-то образом получать доступ к элементам, хранящимся в списке. Однако, в отличие от vector, в классе list нет оператора индексации. Это объясняется тем, что элементы списка хранятся не в непрерывном участке памяти. Для доступа к отдельным элементам класс list использует итераторы. Рассмотрим пример:
#include <vector>
#include <iostream.h>
using namespace std;
void main()
{
list<int> l;
list<int>::iterator i;
l.push_back(10);
l.push_back(20);
l.push_back(30);
cout << "The list is now:";
for(i = l.begin(); i != l.end(); i++)
cout << " " << *i;
}
Вывод программы:
The list is now: 10 400 30
В данной программе i – итератор. Обратите внимание, что он объявлен с указанием соответствующего класса. Дело в том, что итераторы зависят от типа данных, на которые они указывают. Итератор можно понимать как особый вид указателя на элемент списка. После того, как список заполнен тремя числами, его содержимое в цикле выводится на экран. Функция-член begin() возвращает итератор, указывающий на первый элемент списка. В цикле итератор i инициализируется именно этим значением. Цикл продолжается, пока итератор i не примет значение, возвращаемое функцией-членом end(), которая возвращает итератор, указывающий на элемент, следующий за последним в списке. Для навигации по элементам списка к итератору i применяется оператор ++. С помощью операции *, примененной к итератору i, обеспечивается доступ непосредственно к значению элемента списка. С помощью итераторов также можно присваивать значения элементам списка.
Как было сказано, в список можно добавлять и удалять элементы на любой позиции. Для этого используются функции-члены insert() и erase() соответственно. Рассмотрим пример на добавление элементов:
#include <iostream.h>
#include <list>
using namespace std;
void main()
{
list<int> l;
list<int>::iterator i;
l.push_back(10);
l.push_back(20);
l.push_back(30);
cout << "l =";
for(i = l.begin(); i != l.end(); i++)
cout << " " << *i;
cout << endl;
i = l.begin();
i++;
l.insert(i, 999);
cout << "l =";
for(i = l.begin(); i != l.end(); i++)
cout << " " << *i;
cout << endl;
}
Вывод программы:
l = 10 20 30
l = 10 999 20 30
Для указания позиции, куда будет добавлен элемент, используется итератор. Выражение i = l.begin(); присваивает i адрес первого элемента списка. Выражение i++; приводит к тому, что i теперь указывает на второй элемент списка. Поэтому при вызове функции insert() значение 999 добавляется на вторую позицию. Важно понимать, что при этом список увеличивается, т.е. элемент, ранее стоявщий вторым, теперь является третьим, третий – четвертым и т.д.
Пример с удалением элементов из списка:
#include <iostream.h>
#include <list>
using namespace std;
void main()
{
list<int> l;
list<int>::iterator i;
l.push_back(10);
l.push_back(20);
l.push_back(30);
l.push_back(40);
l.push_back(50);
cout << "The initial list is:";
for(i = l.begin(); i != l.end(); i++)
cout << " " << *i;
cout << endl;
l.erase(l.begin());
cout << "After erasing the first element, the list becomes:";
for(i = l.begin(); i != l.end(); i++)
cout << " " << *i;
cout << endl;
i = l.begin();
i++;
l.erase(i);
cout << "After erasing the new second element the list becomes: ";
for(i = l.begin(); i != l.end(); i++)
cout << " " << *i;
cout << endl;
}
Вывод программы:
The initial list is: 10 20 30 40 50
After erasing the first element, the list becomes: 20 30 40 50
After erasing the new second element the list becomes: 20 40 50
Для указания удаляемых из списка элементов также используются итераторы. После заполнения списка в приведенной выше программе и вывода его содержимого на экран команда l.erase(l.begin()); вызывает удаление первого элемента списка. Затем, после вывода содержимого списка на экран, пара команд i = l.begin(); i++; приводят к тому, что i указывает на второй элемент полученного списка. Команда l.erase(i); вызывает удаление этого второго элемента списка.
Другие полезные функции-члены класса list:
clear() – очищает список, т.е. удаляет все хранящиеся в нем элементы;
empty() – возвращает истину, если в списке нет элементов, т.е. если он пустой;
front() – возвращает ссылку на первый элемент списка;
push_front() – добавляет элемент в начало списка;
pop_front() – удаляет первый элемент списка;
pop_back() – удаляет последний элемент списка.