Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Результаты выполнения этой программы таковы.
Размер = 0 Текущее содержимое: Новый размер = 10 0 1 2 3 4 5 6 7 8 9 Новый размер = 20 Текущее содержимое: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 Содержимое удвоено: 0 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 Рассмотрим внимательно код этой программы. В функции main() создается вектор v для хранения int-элементов. Поскольку при его создании не было предусмотрено никакой инициализации, вектор v получился пустым, а его емкость равна нулю. Другими словами, мы создали вектор нулевой длины. Это подтверждается вызовом функции-члена size(). Затем, используя функцию-член push_back(), в конец этого вектора мы помещаем 10 элементов, что заставляет вектор увеличиться в размере, чтобы разместить новые элементы. Теперь размер вектора стал равным 10. Обратите внимание на то, что для отображения содержимого вектора v используется стандартная запись индексации массивов. После этого в вектор добавляются еще 10 элементов, и вектор v автоматически увеличивается в размере, чтобы и их принять на хранение. Наконец, используя опять-таки стандартную запись индексации массивов, мы изменяем значения элементов вектора v. Обратите также внимание на то, что для управления циклами, используемыми для отображения содержимого вектора v и его модификации, в качестве признака их завершения применяется значение размера вектора, получаемое с помощью функции v.size(). Одно из преимуществ векторов перед массивами состоит в том, что у нас есть возможность узнать текущий размер вектора, что в определенных ситуациях является очень полезным средством. Доступ к вектору с помощью итератора Как вы знаете, массивы и указатели в C++ тесно связаны между собой. К элементам массива можно получить доступ как с помощью индекса, так и с помощью указателя. В библиотеке STL аналогичная связь существует между векторами и итераторами. Это значит, что к членам вектора можно обращаться как с помощью индекса, так и с помощью итератора. Эта возможность демонстрируется в следующей программе. // Доступ к вектору с помощью итератора. #include < iostream> #include < vector> using namespace std; Int main() { vector< char> v; // создание массива нулевой длины int i; // Помещаем значения в вектор. for(i=0; i< 10; i++) v.push_back('A' + i); /* Получаем доступ к содержимому вектора с помощью индекса. */ for(i=0; i< 10; i++) cout < < v[i] < < " "; cout < < endl; /* Получаем доступ к содержимому вектора с помощью итератора. */ vector< char>:: iterator р = v.begin(); while(p! = v.end()) { cout < < *p < < " "; p++; } return 0; } Вот как выглядят результаты выполнения этой программы. A B C D E F G H I J A B C D E F G H I J В этой программе сначала создается вектор нулевой длины. Затем с помощью функции push_back() в конец вектора помещаются символы, в результате чего размер вектора соответствующим образом увеличивается. Обратите внимание на то, как объявляется итератор р. Тип этого итератора определяется контейнерными классами. Поэтому для получения итератора для конкретного контейнера используйте объявление, аналогичное показанному в этом примере: просто укажите для данного итератора имя контейнера. В нашей программе итератор p инициализируется таким образом, чтобы он указывал на начало вектора (с помощью функции-члена begin()). Итератор, который возвращает эта функция, можно затем использовать для поэлементного доступа к вектору, инкрементируя его соответствующим образом. Этот процесс аналогичен тому, как можно использовать указатель для доступа к элементам массива. Чтобы определить, когда будет достигнут конец вектора, используется функция-член end(). Эта функция возвращает итератор, установленный за последним элементом вектора. Поэтому, если значение р равно v.end(), значит, конец вектора достигнут. Вставка и удаление элементов из вектора Помимо занесения новых элементов в конец вектора, у нас есть возможность вставлять элементы в середину вектора, используя функцию insert(). Удалять элементы можно с помощью функции erase(). Использование функций insert() и erase() демонстрируется в следующей программе. // Демонстрация вставки элементов в вектор и удаления их из него. #include < iostream> #include < vector> using namespace std; Int main() { vector< char> v; unsigned int i; for(i=0; i< 10; i++) v.push_back('A' + i); // Отображаем исходное содержимое вектора. cout < < " Размер = " < < v.size() < < endl; cout < < " Исходное содержимое вектора: "; for(i=0; i< v.size(); i++) cout < < v[i] < < " "; cout < < endl < < endl; vector< char>:: iterator p = v.begin(); p += 2; // указатель на 3-й элемент вектора // Вставляем 10 символов 'X' в вектор v. v.insert(p, 10, 'X'); /* Отображаем содержимое вектора после вставки символов. */ cout < < " Размер вектора после вставки = " < < v.size()< < endl; cout < < " Содержимое вектора после вставки: "; for(i=0; i< v.size(); i++) cout < < v[i] < < " "; cout < < endl < < endl; // Удаление вставленных элементов. p = v.begin(); p += 2; // указатель на 3-й элемент вектора v.erase(р, р+10); // Удаляем 10 элементов подряд. /* Отображаем содержимое вектора после удаления символов. */ cout < < " Размер вектора после удаления символов = " < < v.size() < < endl; cout < < " Содержимое вектора после удаления символов: "; for(i=0; i< v.size(); i++) cout < < v[i] < < " "; cout < < endl; return 0; } При выполнении эта программа генерирует следующие результаты. Размер = 10 Исходное содержимое вектора: A B C D E F G H I J Размер вектора после вставки = 20 Содержимое вектора после вставки: A B X X X X X X X X X X C D E F G H I J Размер вектора после удаления символов = 10 Содержимое вектора после удаления символов: A B C D E F G H I J Сохранение в векторе объектов класса В предыдущих примерах векторы служили для хранения значений только встроенных типов, но этим их возможности не ограничиваются. В вектор можно помещать объекты любого типа, включая объекты классов, создаваемых программистом. Рассмотрим пример, в котором вектор используется для хранения объектов класса three_d. Обратите внимание на то, что в этом классе определяются конструктор по умолчанию и перегруженные версии операторов " < " и " ==" . Имейте в виду, что, возможно, вам придется определить и другие операторы сравнения. Это зависит от того, как используемый вами компилятор реализует библиотеку STL. // Хранение в векторе объектов класса. #include < iostream> #include < vector> using namespace std; class three_d { int x, y, z; public: three_d() { x = у = z = 0; } three_d(int a, int b, int с) { x = a; у = b; z = c; } three_d & operator+(int a) { x += a; у += a; z += a; return *this; } friend ostream & operator< < (ostream & stream, three_d obj); friend bool operator< (three_d a, three_d b); friend bool operator==(three_d a, three_d b); }; /* Отображаем координаты X, Y, Z с помощью оператора вывода для класса three_d. */ ostream & operator< < (ostream & stream, three_d obj) { stream < < obj.x < < ", "; stream < < obj.у < < ", "; stream < < obj.z < < " "; return stream; } bool operator< (three_d a, three_d b) { return (a.x + a.у + a.z) < (b.x + b.y + b.z); } bool operator==(three_d a, three_d b) { return (a.x + a.у + a.z) == (b.x + b.y + b.z); } Int main() { vector< three_d> v; unsigned int i; // Добавляем в вектор объекты. for(i=0; i< 10; i++) v.push_back(three_d(i, i+2, i-3)); // Отображаем содержимое вектора. for(i=0; i< v.size(); i++) cout < < v[i]; cout < < endl; // Модифицируем объекты в векторе. for(i=0; i< v.size(); i++) v [i] = v[i] + 10; // Отображаем содержимое модифицированного вектора. for(i=0; i< v.size(); i++) cout < < v[i]; return 0; } Эта программа генерирует такие результаты. 0, 2, -3 1, 3, -2 2, 4, -1 3, 5, 0 5, 7, 2 6, 8, 3 7, 9, 4 8, 10, 5 9, 11, 6 10, 12, 7 11, 13, 8 12, 14, 9 13, 15, 10 14, 16, 11 15, 17, 12 16, 18, 13 17, 19, 14 18, 20, 15 19, 21, 16 Векторы обеспечивают безопасность хранения элементов, обнаруживая при этом чрезвычайную мощь и гибкость их обработки, но уступают массивам в эффективности использования. Поэтому для большинства задач программирования чаще отдается предпочтение обычным массивам. Однако возможны ситуации, когда уникальные особенности векторов оказываются важнее затрат системных ресурсов, связанных с их использованием. О пользе итераторов Частично сила библиотеки STL обусловлена тем, что многие ее функции используют итераторы. Этот факт позволяет выполнять операции с двумя контейнерами одновременно. Рассмотрим, например, такой формат векторной функции insert(). template < class InIter> void insert(iterator i, InIter start, InIter end); Эта функция вставляет исходную последовательность, определенную параметрами start и end, в приемную последовательность, начиная с позиции i. При этом нет никаких требований, чтобы итератор i относился к тому же вектору, с которым связаны итераторы start и end. Таким образом, используя эту версию функции insert(), можно один вектор вставить в другой. Рассмотрим пример. // Вставляем один вектор в другой. #include < iostream> #include < vector> using namespace std; Int main() { vector< char> v, v2; unsigned int i; for(i=0; i< 10; i++) v.push_back('A' + i); // Отображаем исходное содержимое вектора. cout < < " Исходное содержимое вектора: "; for(i=0; i< v.size(); i++) cout < < v[i] < < " "; cout < < endl < < endl; // Инициализируем второй вектор. char str[] = " -STL — это сила! -"; for(i=0; str[i]; i++) v2.push_back (str [i]); /* Получаем итераторы для середины вектора v, а также начала и конца вектора v2. */ vector< char>:: iterator р = v.begin()+5; < char>:: iterator p2start = v2.begin(); vector< char>:: iterator p2end = v2.end(); // Вставляем вектор v2 в вектор v. v.insert(p, p2start, p2end); // Отображаем результат вставки. cout < < " Содержимое вектора v после вставки: "; for(i=0; i< v.size(); i++) cout < < v[i] < < " "; return 0; } Популярное:
|
Последнее изменение этой страницы: 2016-03-17; Просмотров: 1236; Нарушение авторского права страницы