Клас string

У мові C++ для представлення і обробки рядків є дві можливості.

По-перше, можна використовувати символьний масив, що закінчується нулем і є рядком в стилі мови C, як це й робилося практично у всіх прикладах даної книги.

По-друге, для роботи з рядками можна використовувати об'єкти бібліотечного класу string з бібліотеки <string>. В цій бібліотеці ім'я string оголошено в просторі імен std і є коротким ім'ям конкретизації більш загального класу-шаблону basic_string:

 

typedef basic_string<char> string;

 

Насправді в класу basic_string є дві конкретизації класу: згаданий клас string, який підтримує рядки 8-розрядних символів, і клас wstring, який підтримує рядки широких (16-розрядних) символів. Оскільки при звичайному програмуванні частіше всього використовуються 8-розрядні символи, далі розглядатиметься тільки конкретизація string шаблонного класу basic_string.

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

 

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

s1 = "Добрий "; // таке присвоювання не допускається

s2 = "день!"; // теж не допускається

s3 = si + s2; // помилка, знову не допускається

 

Для символьного рядка в стилі C не можна використовувати оператор “=” для присвоювання нового значення, за винятком ініціалізації, а для конкатенації двох рядків не можна використовувати оператор складання. Такі операції доводиться виконувати за допомогою показаних нижче бібліотечних функцій:

 

strcpy(s1, "Добрий ");

strcpy(s2, "день!");

strcpy(s3, s1);

strcat(s3, s2);

 

Оскільки символьні масиви, що закінчуються нулем, за своєю суттю технічно не є типами даних, до них не можна застосовувати оператори C++. Це призводить до того, що навіть самі елементарні операції з рядками стають надзвичайно заплутаними. Неможливість використання стандартних операторів C++ для роботи з символьними масивами, що закінчуються нулем, і стала основною причиною включення в стандартну бібліотеку рядкового класу.

Коли в C++ оголошується клас, для цього нового класу можна перевантажувати практично всі оператори. Таким чином, шляхом додавання до бібліотеки стандартного класу string стає можливим обробляти рядки в мові C++ таким самим чином, яким обробляються дані інших типів, а саме за допомогою операторів.

Є, проте, і ще один довід на користь використання стандартного класу string — це безпечне програмування. Недосвідчений або необережний програміст може дуже легко вийти за межі масиву, в якому зберігається рядок, що закінчується нулем.

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

Остаточно, для включення в бібліотеку стандартного класу string є три головні причини:

сумісність, оскільки рядок стає типом даних в C++;

зручність, оскільки тепер можна використовувати стандартні оператори C++;

нарешті, безпека, оскільки межі масиву контролюються і не порушуються.

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

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

Хоча рядковий клас традиційно не вважається частиною бібліотеки стандартних шаблонів STL (див. підрозділ 8.4), проте, він є класом-контейнером. Це, зокрема, означає, що він підтримує алгоритми бібліотеки STL. Зокрема, в класі string підтримуються функції begin() і end(), що повертають відповідно ітератор початку й кінця рядка. Також підтримується функціяsize(), що повертає поточне число символів рядка.

Окрім цього, для обробки рядків є додаткові можливості. Щоб дістати доступ до класу string, в програму слід включити директиву:

 

#include <string>

 

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

8.3.1 Основні конструктори

В класі string є декілька конструкторів. Нижче представлені прототипи трьох з них, які частіше за все використовуються в програмах:

 

string();

string(const char *str);

string(const string &str);

 

В першому варіанті за допомогою конструктора створюється порожній об'єкт типу string.

В другому варіанті об'єкт типу string створюється з рядка в стилі C, що закінчується нулем, заданого вказівником на його перший символ; цей конструктор є конструктором приведення рядка, що закінчується нулем, до об'єкту типу string.

В третьому варіанті об'єкт типу string створюється з іншого об'єкту типу string, тобто цей варіант конструктора є конструктором копіювання.

8.3.2 Основні| оператори

В табл. 8.1 перелічені найбільш часто використовувані оператори, перевантажені для роботи з об'єктами типу string.

 

Таблиця 8.1

Основні оператори для роботи з рядками

Оператор Виконувана операція
= Присвоювання рядка
+ Конкатенація рядків
+= Присвоювання з конкатенацією рядків
== Перевірка на рівність рядків
!= Перевірка на нерівність рядків
< Перевірка на те, чи лівий рядок менше правого
<= Перевірка на те, чи лівий рядок менше або рівний правому
> Перевірка на те, чи лівий рядок більше правого
>= Перевірка на те, чи лівий рядок більше або рівний правому
[] Вибірка по індексу
<< Вивід рядка
>> Ввід рядка

 

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

Оператор + можна використовувати для конкатенації об'єкту типу string з іншим об'єктом типу string або для конкатенації об'єкту типу string з рядком в стилі С. Підтримуються наступні комбінації операндів:

 

string + string

string + C-string

C-string + string

 

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

Нижче наведений короткий приклад використання рядкового класу:

 

#include <iostream>

#include <string>

using namespace std;

int main()

{

string str1("Добридень ");

string str2("мир!");

string str3;

// присвоювання рядків

str3 = str1;

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

// конкатенація двох рядків

str3 = strl + str2;

cout << str3 << "n";

// порівняння рядків

if(str3 > str1)

cout << "str3 > str1n";

if(str3 == str1+ str2)

cout << "str3 == str1+ str2n";

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

str1 = "Це звичайний рядок n";

cout << str1;

// створення рядкового об'єкту за допомогою іншого

// рядкового об'єкту

string str4(str1);

cout << str4;

// ввід рядка

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

cin >> str4;

cout << str4;

return 0;

}

 

Після виконання програми на екрані з'явиться наступне:

 

Добридень

Добридень

Добридень, мир!

str3 > str1

str3 == str1 + str2

Це звичайний рядок

Це звичайний рядок

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

Привіт

 

З програми видно, що з об'єктами типу string можна поводитися так само, як і з вбудованими типами даних мови C++. Це фактично і є головне достоїнство рядкового класу.

 

8.4 STL - стандартна бібліотека шаблонів мови C++

Стандартна бібліотека шаблонів STL (Standard Template Library) включає набір різноманітних контейнерів, які параметризуються, ітератори та багато узагальнених алгоритмів.