Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
+ООП_Навч_посібник.doc
Скачиваний:
8
Добавлен:
01.07.2025
Размер:
6.58 Mб
Скачать

22.6.5. Дослідження алгоритмів

Описані вище алгоритми є тільки малою частиною всього вмісту бібліотеки STL. І звичайно ж, Вам потрібно самим досліджувати інші алгоритми. Заслуговують уваги, наприклад, такі, як set_union() і set_difference(). Вони призначені для оброблення вмісту такого контейнера, як множина. Цікаві також алгоритми next_permutation() і prev_permutation(). Вони створюють наступну і попередню перестановки елементів заданої послідовності. Час, витрачений на вивчення алгоритмів бібліотеки STL, – це час, витрачений не дарма!

22.7. Використання класу string

Як уже зазначалося вище, мова програмування C++ не підтримує вбудований рядковий тип. Проте він надає два способи оброблення рядків. По-перше, для представлення рядків можна використовувати традиційний символьний масив, що завершується нулем. Рядки, що створюються у такий спосіб (він Вам вже знаком), іноді називають С-рядками. По-друге, можна використовувати об'єкти класу string, і саме цей спосіб розглядається у цьому розділі.

Клас string забезпечує альтернативу для рядків, що мають завершальний нуль-символ.

Насправді клас string є спеціалізацію більш загального шаблонного класу basic_string. Існує дві спеціалізації типу basic_string: тип string, який підтримує 8-бітові символьні рядки, і тип wstring, який підтримує рядки, утворені двобайтовими символами. Найчастіше у звичайному програмуванні використовуються рядкові об'єкти типу string. Для використання рядкових класів C++ необхідно приєднати до програми заголовок <string>.

Перш ніж розглядати клас string, важливо зрозуміти, чому він є частиною С++-библиотеки. Стандартні класи не відразу були додані у визначення мови програмування C++. Насправді кожному нововведенню передували серйозні дискусії і запеклі суперечки. При тому, що C++ вже містить підтримку рядків у вигляді масивів, що завершуються нулем, внесення класу string у мові програмування C++, на перший погляд, може видатися винятком з цього правила. Але це далеко не так. І ось чому: рядки, що мають завершальний нуль-символ, не можна обробляти стандартними С++-операторами, і їх не можна використовувати у звичайних С++-виразах. Розглянемо, наприклад, такий фрагмент коду програми:

char s1[80], s2[80], s3[80];

s1 = "один"; // так робити не можна

s2 = "два"; // так робити не можна

s3 = s1 + s2; // помилка

Як зазначено у коментарях до цієї програми, y мові програмування C++ неможливо використовувати оператор присвоєння для додання символьному масиву нового значення (за винятком настанови| ініціалізації), а також не можна застосовувати оператор додавання "+" для конкатенації двох рядків Ці операції можна виконати за допомогою бібліотечних функцій.

strcpy(s1, "one");

strcpy(s2, "two");

strcpy(s3, s1);

strcpy(s3, s2);

Оскільки символьний масив, що завершується нулем, формально не є саме самостійним типом даних, до нього не можна застосувати С++-оператори. Це позбавляє "вишуканості" навіть самі елементарні операції з рядками. І саме нездатність обробляти рядки, що мають завершальний нуль-символ, за допомогою стандартних С++-операторів при вела до розробки стандартного рядкового класу. Пригадайте: створюючи клас у мові програмування C++, ми визначаємо новий тип даних, який можна повністю інтегрувати у С++-среду Це, звичайно ж, означає, що для нового класу можна перевантажувати оператори. Таким чином, вводячи в мову стандартний рядковий клас, ми створюємо можливість для оброблення рядків так само, як і даних будь-якого іншого типу, а саме за допомогою операторів.

Проте існує ще одна причина, що реабілітує створення стандартного класу string: безпека. Руками недосвідченого або необережного програміста дуже ліг до забезпечити вихід за межі масиву, який містить рядок з тим, що завершує нулем. Розглянемо, наприклад, стандартну функцію копіювання strcpy(). Ця функція не передбачає механізм перевірки факту порушення меж масиву приймача. Якщо початковий масив містить більше символів, ніж може прийняти масив приймач, то в результаті цієї помилки дуже вірогідна повна відмова системи. Як буде-показано нижче, стандартний клас string не допускає виникнення подібних помилок

Отже, існує три причини для внесення у мові програмування C++ стандартного класу string несуперечність даних (рядок тепер визначається самостійним типом даних), зручність (програміст може використовувати стандартні С++-оператори) і безпечність (межі масивів відтепер не порушуватимуться). Необхідно мати на увазі, що все вище перераховане не означає, що програміст повинен відмовлятися від використання звичайних рядків, що мають завершальний нуль-символ. Вони, як і раніше, залишаються найбільш ефективним засобом реалізації рядків. Але, якщо швидкість не є для Вас визначальним фак|тором, використання нового класу string дасть Вам доступ до безпечного і повністю інтегрованому способу оброблення рядків.

І хоча клас string традиційно не сприймається як частина бібліотеки STL, він проте, є ще один контейнерний клас, визначено C++ Це означає, що він підтримує алгоритми, описані у попередньому розділі. Dpi цьому рядки мають додаткові можливості. Для отримання доступу до класу string необхідно приєднати до програми заголовок <string>.

Клас string дуже великої, він містить багато конструкторів і функцій членів. Окрім того, багато функцій-членів класу мають декілька перевантажених форм. Оскільки в одному розділі неможливо розглянути весь вміст класу string, ми звернемо Вашу увагу тільки на найпопулярніших його засобах. Отримавши загальне представлення про роботу класу string, Ви зможете легко розібратися в інших його можливостях самі.

Прототипи трьох найпоширеніших конструкторів класу string мають ледве дуючий вигляд.

string();

string(const char *str);

string(const string &str);

Перша форма конструктора створює порожній об'єкт класу string. Друга форма створює string-об'єкт з рядка, що завершується нульовим символом, який адресується параметром str. Ця форма конструктора забезпечує перетворення з рядка, що завершується нульовим символом в об'єкт типу string. Третя створює string-об'єкт з іншого string-об'єкта.

Для об'єктів класу string визначено такі оператори.

Оператор

Опис

=

Присвоєння

+

Конкатенація

+=

Присвоєння з конкатенацією

==

Рівність

!=

Нерівність

<

Менше

< =

Менше або рівно

>

Більше

>

Більше або рівно

[]

Індексація

"

Введення

"

Введення

Ці оператори дають змогу використовувати об'єкти типу string у звичайних виразах і позбавляють програміста від потреби викликати такі функції, як strcpy() або strcpy(). У загальному випадку у виразах можна змішувати string-об'єкти і рядки, що мають завершальний нуль-символ. Наприклад, string-об'єкт можна присвоїти рядку, що завершується нулем.

Оператора додавання "+" можна використовувати для конкатенації одного string-об'єкта з іншим або string-об'єкта з рядком, створеним у С-стіле (С-рядком). Іншими словами, підтримуються наступні операції.

str ing-об'єкт + string-об'єкт

string-об'єкт + С-рядок

С-рядок+ string-об'єкт

Оператор додавання "+" дає змогу також додавати символ у кінець рядка.

У класі string визначена константа прози, яка дорівнює -1. Вона представляє розмір рядка максимально можливої довжини.

Рядковий клас C++ істотно полегшує оброблення рядків. Наприклад, використовуючи string-об'єкти, можна застосовувати оператор присвоєння для призначення string-об'єкту рядка в лапках, оператор додавання "+" для конкатенації рядків і оператори порівняння для порівняння рядків. Виконання цих операцій продемонстровано у наведеному нижче коді програми.

Код програми 22.17. Демонстрація механізму використання класу string для оброблення рядків

#include <vcl>

#include <iostream> // Для потокового введення-виведення

#include <conio> // Для консольного режиму роботи

#include <string> // Для роботи з рядками

using namespace std; // Використання стандартного простору імен

int main()

{

string str1 ("Клас string дає змогу ефективно ");

string str2("обробляти рядки.");

string str3;

// Присвоєння string-об'єкта

str3 = str1;

cout << str1 << "\n" << str3 << "\n";

// Конкатенація двох string-об'єктів.

str3 = str1 + str2;

cout << str3 << "\n";

// Порівняння string-об'єктів.

if(str3 > str1) cout << "str3 > str1\n";

if(str3 == str1+str2)

cout << "str3 == str1+str2\n";

// Об'єкту класу string можна також присвоїти звичайний рядок.

str1 = "Це рядок, що завершується нульовим символом.\n";

cout << str1;

// Створення string-об'єкта за допомогою іншого string-об'єкта.

string str4(str1);

cout << str4;

// Введення рядка.

cout << "Введіть рядок: "; cin >> str4;

cout << str4;

getch(); return 0;

}

У процесі виконання ця програма відображає на екрані такі результати:

Клас string дає змогу ефективно

Клас string дає змогу ефективно

Клас string дає змогу ефективно обробляти рядки.

str3 > str1

str3 == str1+str2

Це рядок, що завершується нульовим символом.

Це рядок, що завершується нульовим символом.

Введіть рядок: Привіт

Привіт

Звернемо Вашу увагу на те, як легко тепер виконується обробка рядків. Наприклад, оператор додавання "+" використовують для конкатенації рядків, а оператор ">" для порівняння двох рядків. Для виконання цих операцій з використанням С-стилю оброблення рядків, тобто використання рядків, що мають завершальний нуль-символ, довелося б застосовувати менш зручні засоби, а саме викликати функції streat() і strcmp(). Оскільки С++-об'єкти типу string можна вільно змішувати з С-рядками, їх (string-об'єкти) можна використовувати в будь-якій програмі не тільки без жодного збитку для ефективності, але навіть з помітним виграшем.

Важливо також відзначити, що у попередній програмі розмір рядків не задається. Об'єкти типу string автоматично отримують розмір, потрібний для зберігання заданого рядка. Таким чином, у процесі виконання операцій присвоєння або конкатенації рядків рядок-приймач збільшиться по довжині настільки, наскільки це необхідно для зберігання нового вмісту рядка. При обробленню string-об'єктів неможливо вийти за межі рядка. Саме цей динамічний аспект string-об'єктів вигідно відрізняє їх від рядків, що мають завершальний нуль-символ (які часто страждають від порушення меж).