
- •Міністерство надзвичайних ситуацій України Львівський державний університет безпеки життєдіяльності Юрій грицюк, Тарас рак
- •Навчальний посібник
- •Потреба використання об'єктно-орієнтованого програмування
- •Поняття про об’єктно-орієнтований підхід до розроблення складних програм
- •Основні компоненти об’єктно-орієнтованої мови програмування
- •Поняття про універсальну мову моделювання
- •Базові поняття класу
- •Код програми 2.1. Демонстрація механізму оголошення класу та його застосування
- •Поняття про конструктори і деструктори
- •Особливості реалізації механізму доступу до членів класу
- •Класи і структури - споріднені типи
- •Об'єднання та класи - споріднені типи
- •Поняття про вбудовані функції
- •Inline int myClass::Put() return c;
- •Особливості організації масивів об'єктів
- •Особливості використання покажчиків на об'єкти
- •Поняття про функції-"друзі" класу
- •Код програми 3.1. Демонстрація механізму використання "дружньої" функції для доступу до закритих членів класу
- •Код програми 3.2. Демонстрація механізму використання "дружньої" функції для перевірки статусу кожного об'єкта
- •Void Run(); //Таймер відліку часу
- •Void timerClass::Run()
- •Int mainO
- •Особливості механізму динамічної ініціалізації конструктора
- •Int s; public:
- •Void Run(); //Таймер відліку часу
- •Void timerClass::Run()
- •Int mainO
- •Особливості механізму присвоєння об'єктів
- •Int а, ь; public:
- •Int mainO
- •Особливості механізму передачі об'єктів функціям
- •Void Fun(myClassobj)
- •Int mainO
- •Конструктори, деструктори і передача об'єктів
- •Void Get(myClass obj)
- •Int mainO
- •Потенційні проблеми, які виникають при передачі об'єктів
- •Int *р; public:
- •Void Get(myClass &obj) // Передача об'єкта за посиланням
- •Int mainO
- •Особливості механізму повернення об'єктів функціями
- •Void Set(char*s) {strcpy(str, s);}
- •Void Show() {cout «"Рядок:" « str« endl;}
- •Int mainO
- •Int mainO
- •Механізми створення та використання конструктора копії
- •Використання конструктора копії для ініціалізації одного об'єкта іншим
- •Int mainO
- •Механізм використання конструктора копії для передачі об'єкта функції
- •Int mainO
- •Механізм використання конструктора копії при поверненні функцією об'єкта
- •Int mainO
- •3.7.4. Конструктори копії та їх альтернативи
- •Поняття про ключове слово this
- •Void Fun() {...};
- •Int mainO
- •Механізми перевизначення операторів з використанням функцій-членів класу
- •Int х, у, z; //Тривимірні координати
- •Int mainO
- •Intх,у,z; //Тривимірні координати
- •Void Show(char*s);
- •Int mainO
- •Int х, у, z; //Тривимірні координати
- •Int mainO
- •Особливості реалізації механізму перевизначення операторів
- •Механізми иеревизначення операторів з використанням функцій-не членів класу
- •Використання функцій-"друзів" класу для перевизначення бінарних операторів
- •Void Show(char*s);
- •Int mainO
- •Int mainO
- •Використання функцій-"друзів" класу для перевизначення унарних операторів
- •Int mainO
- •Особливості реалізації оператора присвоєння
- •Int mainO
- •Int mainO
- •Механізми перевизначення оператора індексації елементів масиву "[]"
- •Int mainO
- •Int aMas[size]; public:
- •Int mainO
- •Int aMas[size]; public:
- •Int mainO
- •Механізми перевизначення оператора виклику функцій "()"
- •Int mainO
- •Механізми перевизначення рядкових операторів
- •Конкатенація та присвоєння класу рядків з рядками класу
- •Void Show(char*s) {cout« s « string « endl;}
- •Конкатенація та присвоєння класу рядків з рядками, що закінчуються нульовим символом
- •Void Show(char*s) {cout« s « string « endl;}
- •Void Show(char*s) {cout« s « string « endl;}
- •Int mainO
- •Поняття про успадкування в класах
- •Int kolesa; // Кількість коліс int pasagyr; // Кількість пасажирів public:
- •Int mistkist; // Вантажомісткість у м куб. Public:
- •Int kolesa; // Кількість коліс int pasagyr; // Кількість пасажирів public:
- •Int mainO
- •Використання специфікатора доступу protected для надання членам класу статусу захищеності
- •Int mainO
- •Int mainO
- •Int d; // Захищений public:
- •Int mainO
- •Protected-членом класу derived, що робить його недоступним за його межами. */
- •Void showX() {cout« х « endl;}
- •Void showY() {cout« у « endl;}
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Успадкування віртуальних функцій
- •Void Show() {cout« Суг("Другий похідний клас.") « endl;}
- •Virtual void Show() {cout« Суг("Базовий клас.") « endl;}
- •Void Show() {cout« Суг("Перший похідний клас. ")« endl;}
- •Int mainO
- •Virtual void ShowO {cout« Суг("Базовий клас.") « endl;}
- •Void Show() {cout« Суг("Перший похідний клас. ")« endl;}
- •Int mainO
- •Void Show()
- •Void Show()
- •Int mainO
- •Void Show()
- •Void Show()
- •Int mainO
- •Void swapAb(aType &а, аТуре &b)
- •Int mainO
- •Приклад створення узагальненого класу для організації безпечного масиву
- •Int mainO
- •Використання в узагальнених класах аргументів, що не є узагальненими типами
- •Використання в шаблонних класах аргументів за замовчуванням
- •Int mainO
- •Механізм реалізації безпосередньо заданої спеціалізації класів
- •Int mainO
- •Основні особливості оброблення виняткових ситуацій
- •Системні засоби оброблення винятків
- •Xtest(1);
- •Xtest(2);
- •Перехоплення винятків класового типу
- •Використання декількох catch-наетанов
- •Варіанти оброблення винятків
- •Перехоплення всіх винятків
- •Накладання обмежень на тип винятків, які генеруються функціями
- •Int mainO
- •Xhandler(o); // Спробуйте також передати функції XhandlerO аргументи 1 і 2.
- •Void Xhandler(int test) throw 0
- •Повторне генерування винятку
- •Int mainO
- •Int mainO
- •Механізми перевизначення операторів new і delete
- •Void *р;
- •Void *p;
- •Int mainO
- •Класи потоків
- •Особливості механізмів перевизначення операторів введення-виведення даних
- •Створення перевюначених операторів виведення даних
- •Int mainO
- •Використання функцій-"друзів" класу для перевюначення операторів виведення даних
- •Int х, у, z; //Тривимірні координати (тепер це private-члени) public:
- •Int mainO
- •Створення перевюначених операторів введення даних
- •Istream &operator»(istream &stream, kooClass &obj)
- •Cout«"Введіть координати X, у і z:
- •Stream » obj.X » obj.Y » obj.Z;
- •Istream &operator»(istream &stream, objectType &obj)
- •// Код операторної функції введення даних
- •Class kooClass {// Оголошення класового типу int х, у, z; // Тривимірні координати
- •Istream &operator»(istream &stream, kooClass &obj)
- •Int mainO
- •Void unsetf(fmtflags flags),
- •Void showflags(ios::fmtflags f); // Відображення поточного стану опцій
- •Int mainO
- •Ios::fmtflags f; // Оголошення параметру для поточного стану опцій
- •Int mainO
- •Створення власних маніиуляторних функцій
- •Організація файлового введення-виведення даних
- •Відкриття та закриття файлу
- •Зчитування та запис текстових файлів
- •Ifstream in(argv[1], ios::in | ios::binary); if(!in){
- •In.CloseO; getchO; return 0;
- •Int mainO
- •Зчитування та записування у файл блоків даних
- •Int mainO
- •Ifstream inftest", ios::in | ios::binary); if(!in){
- •Використання функції eof() для виявлення кінця файлу
- •If(!in.Eof()) cout« ch;
- •In.CloseO; getchO; return 0;
- •Int main(int arge, char *argv[])
- •Ifstream f1(argv[1], ios::in | ios::binary); if(!f1) {
- •Ifstream f2(argv[2], ios::in | ios::binary);
- •Int main(int arge, char *argv[])
- •Ifstream in(argv[1], ios::in | ios::binary); if(!in){
- •In.Seekg(atoi(argv[2]), ios::beg); while(in.Get(ch)) cout« ch; getchO; return 0;
- •Int х, у, z; // Тривимірні координати; вони тепер закриті public:
- •Int mainO
- •Virtual void Fun() {}; // Робимо клас Base поліморфним
- •Int mainO
- •Virtual void FunO {cout«"у класі Base"« endl;}
- •Int mainO
- •Virtual void FunO {}
- •Void derivedOnlyO {cout«"Це об'єкт класу Derived"« endl;}
- •Int mainO
- •Void Fun(const int *р)
- •Int mainO
- •Namespace ns { int d;
- •Застосування настанови using
- •Int Comp(const void *а, const void *b);
- •Int mainO
- •Int Comp(const void *a, const void *b)
- •Int mainO
- •Int Fun10 const; // const-функція-член
- •Int PutO const; return c; // Все гаразд
- •Int mainO
- •0Bj.Set(1900); cout « Obj.PutO;
- •Void setJ(int х) const // Наступна функція не відкомпілюється.
- •Int а; public:
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int myClass::*dp; // Покажчик на int-члена класу void (myClass::*fp)(int X); // Покажчик на функцію-члена
- •Int mainO
- •Механізми роботи з векторами
- •Int mainO
- •1 234 5 678 9 10 11 12 13141516 17 1819 Вміст подвоєно:
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Int mainO
- •Символи н
- •Символів представляють голосні звуки.
- •Int mainO
- •Int mainO
- •Int mainO
- •Void getaLine(string& inStr); // Отримання рядка тексту char getaCharO; //Отримання символу
- •Int aptNumber; // Номер кімнати мешканця
- •Void DisplayO; // Виведення переліку мешканців
- •Int aptNo; float rent[12]; public:
- •Void setRent(int, float); // Запис плати за місяць
- •Void insertRent(int, int, float); void DisplayO;
- •Int month, day; string category, payee; float amount; expense() {}
- •Int mainO
- •Void rentRecord::insertRent(int aptNo, int month, float amount)
- •SetPtrsRr.Insert(ptrRow); // Занести рядок вектор
- •If( setPtrsRr.Empty())
- •Else // Інакше
- •Int month, day; string category, payee; float amount;
- •«" 'Є' для запису витрат:";
- •Навчальний посібник
Int mainO
{
char str[] = "STL-програмування - це сила!"; vector<char> vek; unsigned int i;
for(int i=0; str[i]; І++) vek.push_back(str[i]); cout«"Послідовність:";
for(int i=0; i<vek.sizeO; i++) cout« vek[i]; cout« endl;
int n; charch = 'h';
n = count(vek.begin(), vek.end(), ch); cout« n «" символи« ch « « endl;
n = count_if(vek. beginO, vek.endO, isvowel);
cout« n «" символів представляють голосні звуки"« endl;
getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати: Послідовність: STL-програмування - це сила!
Символи н
Символів представляють голосні звуки.
Програма починається із створення вектора, який містить рядок "STL-програму- вання - це сила!". Потім використовується алгоритм count() для підрахунку кількості букв 'н' у цьому векторі. Після цього викликається алгоритм count_if(), який підраховує кількість символів, що представляють голосні звуки з використанням як предикату функції isvowel(). Зверніть увагу на те, як закодований цей предикат. Всі унарні предикати отримують як параметр об'єкт, тип якого збігається з типом елементів, що зберігаються у контейнері, для якого і створюється цей предикат. Предикат повинен повертати значення ІСТИНА або ФАЛЬШ.
Видалення та заміна елементів
Іноді корисно згенеруватн нову послідовність, яка складатиметься тільки з певних елементів початкової послідовності. Одним з алгоритмів, який може справитися з цим завданням, є remove_copy(). Його загальний формат має такий вигляд: template <class Forlter, class Outlter, class myType>
Outlter remove_copy(lnlter start, Inlter end,
Outlter result, const myType &i/a/);
Алгоритм remove_copyO копіює з вилученням із заданого діапазону елементи, які дорівнюють значенню val, і поміщає результат у послідовність, яка адресується параметром result. Алгоритм повертає ітератор, який вказує на кінець результату. Контейнер-приймач повинен бути достатньо великим, щоби прийняти отриманий результат.
Щоб у процесі копіювання у послідовності один елемент замінити іншим, використовується алгоритм replace_copyO- Його загальний формат має такий вигляд: template <class Forlter, class Outlter, class myType>
Outlter replace_copy(lnlter start, Inlter end,
Outlter result, const myType &old, Const myType &new)\
Алгоритм replace_copy() копіює елементи із заданого діапазону у послідовність, яка адресується параметром result. У процесі копіювання відбувається заміна елементів, які мають значення old, елементами за значенням new. Алгоритм поміщає результат у послідовність, яка адресується параметром result, і повертає ітератор, який вказує на кінець цієї послідовності. Контейнер-приймач повинен бути достатньо великим, щоби прийняти отриманий результат.
У наведеному нижче коді програми продемонстровано механізм використання алгоритмів remove_copyO і replace_copy(). Під час її виконання створюється послідовність символів, з якої видаляються всі букви 'е'. Потім здійснюється заміна всіх букв 'е' буквами 'х'.
Код програми 12.14. Демонстрація механізму використання алгоритмів remove_copy і replace_copy
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio> // Для консольного режиму роботи
#include <vector> // Для роботи з контейнерним класом "Вектор"
#include <algorithm> // Для роботи з алгоритмами бібліотеки STL
using namespace std; // Використання стандартного простору імен
int mainO
{
char str[] = "Це дуже простий тест."; vector<char> vek, vek2(30);
for(int i=0; str[i]; І++) vek.push_back(str[i]);
// **** Демонстрація алгоритму remove_copy ****
cout « "Вхідна послідовність: ";
for(int і=0; i<vek.sizeO; і++) cout« vek[i]; cout« endl;
// Видаляємо всі букви 'є'.
remove_copy(vek.begin(), vek.endO, vek2.begin0, V);
cout«"Після видалення букв 'т': for(int i=0; vek2[i]; І++) cout« vek2[i]; cout« endl« endl;
// **** Демонстрація алгоритму replace_copy ****
cout«"Вхідна послідовність:"; for(int i=0; i<vek.size(); І++) cout« vek[i]; cout« endl;
// Замінюємо букви 'є' буквами 'X'. replace_copy(vek.begin(), vek.endO, vek2.begin0, 'o', 'x');
cout«"Після заміни букв 'e' буквами 'X':"; for(int i=0; vek2[i]; І++) cout« vek2[i]; cout« endl« endl; getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати: Вхідна послідовність: Це дуже простий тест.
Після видалення букв 'е': Ц дуж простий тст.
Вхідна послідовність: Це дуже простий тест.
Після заміни букв 'е' буквами 'X': ЦХ дужХ простий тХст.
Реверсування послідовності
У програмах часто використовують алгоритм reverse(), який у діапазоні, заданому параметрами start і end, змінює порядок слідування елементів на протилежний. Його загальний формат має такий вигляд:
template <class Bilter> void reverse(Bilter start, Bilter end)]
У наведеному нижче коді програми продемонстровано механізм використання цього алгоритму.
#include
<vcl> #include <iostream> #include <conio>
#include <vector> #include <algorithm> using namespace
std;
// Для потокового введення-виведення // Для консольного режиму роботи // Для роботи з контейнерним класом "Вектор" // Для роботи з алгоритмами бібліотеки STL // Використання стандартного простору імен
int mainO
{
vector<int> vek; unsigned int i;
for(int і=0; і<10; І++) vek.push_back(i);
cout«"Початкова послідовність: for(int і=0; i<vek.sizeO; і++) cout« vek[i]«" cout« endl;
reverse(vek. beginO, vek.endO);
cout«"Реверсована послідовність: for(int i=0; i<vek.sizeO; i++) cout« vek[i]«" getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати: Початкова послідовність: 0123456789 Реверсована послідовність: 9876543210
Перетворення послідовності
Одним з найцікавіших є алгоритм перетворення послідовності transform(), який дає змогу модифікувати кожен елемент у діапазоні відповідно до заданої функції. Алгоритм transform() використовується у двох загальних форматах: template <class Inlter, class Outlter, class Func>
Outltertransform(lnlter start, Inlter end,
Outlter result, Func unaryfunc)',
template <class Inlterl, class Inlter2, class Outlter, class Func>
Outltertransform(lnlter1 startl, Inlterl endl,
Inlter2 start2, Outlter result, Func binaryfunc);
Алгоритм transform() застосовує функцію до діапазону елементів і зберігає результат у послідовності, яка задається параметром result. У першій формі діапазон задається параметрами start і end. Використовувана для перетворення функція задається параметром unaryfunc. Вона приймає значення елемента як параметр повертає перетворене значення. У другому форматі алгоритму перетворення здійснюється з використанням бінарної функції, яка приймає як перший параметр значення, призначеного для перетворення елемента з послідовності, а як другий параметр - елемент з другої послідовності. Обидві версії повертають ітератор, який вказує на кінець остаточної послідовності.
У наведеному нижче коді програми використовується проста функція перетворення xformO, яка підносить до квадрату кожен елемент списку. Зверніть увагу на те, що остаточна послідовність зберігається у тому ж списку, який містив початкову послідовність.
Код програми 12.16. Демонстрація механізму використання алгоритму transform()
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio> // Для консольного режиму роботи
#include <list> // Для роботи зі списками
#include <algorithm> // Для роботи з алгоритмами бібліотеки STL
using namespace std; // Використання стандартного простору імен
// Проста функція перетворення, int xform(int і) {
return і * і; // Квадрат початкового значення
}
int mainO
{
list<int> xList; inti;
// Поміщаємо значення у список. for(int і=0; і<10; І++) xList.push_back(i);
cout«"Початковий список xList:"; list<int>::iteratorp = xList.beginO; while(p != xList.endO) {
cout«*p «""; p++;
}
cout« endl;
// Перетворення списку xList.
p = transform(xList.beginO, xListendO, xList.beginO, xform);
cout«"Перетворений список xList:"; p = xList.beginO; while(p != xListendO) { cout«*p «""; p++;
}
getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати: Початковий список xList: 0123456789 Перетворений список xList: 0 1 4 9 16 25 36 49 64 81
Як бачите, кожен елемент у списку xList тепер зведено у квадрат.
Описані вище алгоритми є тільки малою частиною всього вмісту бібліотеки STL. Зазвичай Вам потрібно самим досліджувати інші алгоритми. Заслуговують уваги, наприклад, такі алгоритми, як set_unionO і set_difference(). Вони призначені для оброблення вмісту такого контейнера, як множина. Цікаві також алгоритми next_permutation() і prev_permutation(). Вони створюють наступну і попередню перестановки елементів заданої послідовності. Час, витрачений на вивчення алгоритмів бібліотеки STL, - це час, витрачений не дарма!
Особливості використання об'єктів класу string
Як уже зазначалося вище, мова програмування C++ не підтримує вбудованого рядкованого типу. Проте він надає два способи оброблення рядків. По-перше, для представлення рядків можна використовувати традиційний символьний масив, який завершується нулем. Рядки, що створюються у такий спосіб (Ви вже ознайомлені з ним), іноді називають С-рядками. По-друге, можна використовувати об'єкти класу string, і саме цей спосіб ми зараз розглянемо.
Клас string забезпечує альтернативу для рядків, які мають завершальний нуль-символ.
Насправді клас string є не чим іншим, як спеціалізація більш загального шаблонного класу basic_string. Існує дві спеціалізації типу basic_string: тип string, який підтримує 8-бітові символьні рядки, і тип wstring, який підтримує рядки, утворені двобайтовими символами. Найчастіше у звичайному програмуванні використовують рядкові об'єкти типу string. Для використання рядкових класів C++ необхідно приєднати до програми заголовок <string>.
Клас string - частина С++-бібліотеки
Перед тим, як розглядати особливості роботи з класом string, важливо зрозуміти, чому він є частиною С++-бібліотеки. Стандартні класи не відразу були додані у визначення мови програмування C++. Насправді кожному нововведенню передували серйозні дискусії та запеклі суперечки. При тому, що мова C++ вже містить підтримку рядків у вигляді масивів, що завершуються нулем, внесення класу string у мову програмування C++, на перший погляд, може видатися винятком з цього правила. Але це далеко не так. І ось чому: рядки з завершальним нуль-сим- волом, не можна обробляти стандартними С++-операторами, і їх не можна використовувати у звичайних С++-виразах. Розглянемо, наприклад, такий фрагмент коду програми:
char s1 [80], s2[80], s3[80]; s1 = "один"; // так робити не можна s2 = "два"; // так робити не можна s3 = s1+s2; //Помилка
Як зазначено у коментарях до цього коду програми, у мові програмування C++ неможливо використовувати оператор присвоєння для надання символьному масиву нового значення (за винятком настанови ініціалізації), а також не можна застосовувати операцію додавання "+" для конкатенації двох рядків. Ці операції можна виконати за допомогою бібліотечних функцій. strcpy(s1, "один"); strcpy(s2, "два"); strcpy(s3, s1); strcpy(s3, s2);
Оскільки символьний масив, який завершується нулем, формально не є самостійним типом даних, то до нього не можна застосувати С++-оператори. Це позбавляє "вишуканості" навіть найелементарніші операції з рядками. І саме нездатність обробляти рядки з завершальним нуль-символом, за допомогою стандартних С++-операторів привела до розроблення стандартного рядкового класу. Пригадайте: створюючи клас у мові програмування C++, ми визначаємо новий тип даних, який можна повністю інтегрувати у С++-середовигце. Це, звичайно ж, означає, що для нового класу можна перевизначати оператори. Таким чином, вводячи в мову стандартний рядковий клас, ми створюємо можливість для оброблення рядків так само, як і даних будь-якого іншого типу, а саме за допомогою операторів.
Проте існує ще одна причина, яка реабілітує створення стандартного класу string: безпека. Руками недосвідченого або необережного програміста дуже легко забезпечити вихід за межі масиву, який містить рядок з завершальним нулем. Розглянемо, наприклад, стандартну функцію копіювання strcpy(). Ця функція не передбачає механізм перевірки факту порушення меж масиву приймача. Якщо початковий масив містить більше символів, ніж може прийняти масив приймач, то внаслідок цієї помилки дуже вірогідна повна відмова системи. Як буде показано далі, стандартний клас string не допускає виникнення подібних помилок
Отже, існує три причини для внесення у мову програмування C++ стандартного класу string: несуперечність даних (рядок тепер визначається самостійним типом даних), зручність (програміст може використовувати стандартні С++-опе- ратори) і безпечність (межі масивів відтепер не порушуватимуться). Необхідно мати на увазі, що все перераховане вище зовсім не означає, що програміст повинен відмовлятися від використання звичайних рядків, які мають завершальний нуль-символ. Вони, як і раніше, залишаються найбільш ефективним засобом реалізації рядків. Але, якщо швидкість виконання програми не є для Вас визначальним фактором, то використання нового класу string дасть Вам доступ до безпечного і повністю інтегрованого способу оброблення рядків.
І хоча клас string традиційно не сприймається як частина бібліотеки STL, проте він є ще одним контейнерним класом, який визначено у мові програмування C++. Це означає, що він підтримує алгоритми, описані у попередньому розділі. До того ж, рядки мають додаткові можливості. Для отримання доступу до класу string необхідно приєднати до програми заголовок <string>.
Клас string дуже великий, він містить багато конструкторів і функцій-членів. Окрім цього, багато функцій-членів класу мають декілька перевизначених форм. Оскільки в одному розділі неможливо розглянути весь вміст класу string, ми зверніть увагу тільки на найпопулярніших його засобах. Отримавши загальне уявлення про роботу класу string, Ви зможете легко розібратися в інших його можливостях самі.
Прототипи трьох найпоширеніших конструкторів класу string мають такий вигляд: stringO;
string(constchar*sfr); string(const string &sfr);
Перша форма конструктора створює порожній об'єкт класу string. Друга форма створює string-об'єкт з рядка, який завершується нульовим символом, який адресується параметром str. Ця форма конструктора забезпечує перетворення рядка з завершальним нуль-символом на об'єкт типу string. Третя форма створює string- об'єкт з іншого string-об'єкта.
Оператор |
Опис |
= |
Присвоєння |
+ |
Конкатенація |
+= |
Присвоєння з конкатенацією |
== |
Рівність |
! = |
Нерівність |
< |
Менше |
<= |
Менше або дорівнює |
> |
Більше |
>= |
Більше або дорівнює |
[і |
Індексація |
« |
Введення |
» |
Виведення |
Ці оператори дають змогу використовувати об'єкти типу string у звичайних виразах і позбавляють програміста потреби викликати такі функції, як strcpyO або strcpy(). У загальному випадку у виразах можна змішувати string-об'єкти і рядки з завершальним нуль-символом. Наприклад, string-об'єкт можна присвоїти рядку, що завершується нулем.
Оператор додавання "+" можна використовувати для конкатенації одного string-об'єкта з іншим або string-об'єкта з рядком, створеним у С-стилі (С-рядком). Іншими словами, підтримуються такі операції: string-об'єкг + string-об'єкт string-об'єкт + С-рядок С-рядок + string-об'єкт
Оператор додавання "+" дає змогу також додавати символ у кінець рядка.
У класі string визначено константу npos, яка дорівнює -1. Вона представляє розмір рядка максимально можливої довжини.
Рядковий клас у мові програмування C++ істотно полегшує оброблення рядків. Наприклад, використовуючи string-об'єкти, можна застосовувати оператор присвоєння для призначення string-об'єкту рядка в лапках, оператор конкатенації "+" - для конкатенації рядків і оператори порівняння - для порівняння рядків. Виконання цих операцій продемонстровано у наведеному нижче коді програми.
Код програми 12.17. Демонстрація механізму використання класу string для оброблення рядків
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio> // Для консольного режиму роботи
#include <string> // Для роботи з рядковими типами
using namespace std; // Використання стандартного простору імен
int mainO
{
string strl ("Клас string дає змогу ефективно"); string str2 ("обробляти рядки.");
string str3;
// Присвоєння string-об'єкта str3 = strl;
cout« strl « endl« str3 « endl;
// Конкатенація двох string-об'єктів. str3 = strl + str2; cout« str3 « endl;
// Порівняння string-об'єктів.
if(str3 > strl) cout "str3 ^ strl" endl;
if(str3 == strl + str2)
cout«"str3 == strl + str2"« endl;
// Об'єкту класу string можна також присвоїти звичайний рядок, strl = "Це рядок, який завершується нульовим символом"« endl; cout« strl;
// Створення string-об'єкта за допомогою іншого string-об'єкта, string str4(str1); cout« str4;
// Введення рядка.
cout«"Введіть рядок:"; сіп » str4;
cout« str4;
getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати:
Клас string дає змогу ефективно
Клас string дає змогу ефективно
Клас string дає змогу ефективно обробляти рядки.
str3 > strl
str3 == strl + str2
Це рядок, який завершується нульовим символом.
Це рядок, який завершується нульовим символом.
Введіть рядок: Привіт Привіт
Зверніть увагу на те, як легко тепер здійснюється оброблення рядків. Наприклад, оператор конкатенації "+" використовує для конкатенації рядків, а оператор ">" - для порівняння двох рядків. Для виконання цих операцій з використанням С-стилю оброблення рядків, тобто використання рядків, що мають завершальний нуль-символ, довелося б застосовувати менш зручні засоби, а саме викликати функції streat() і strcmp(). Оскільки С++-об'єкти типу string можна вільно змішувати з С-рядками, то їх (string-об'єкти) можна використовувати в будь-якій програмі не тільки без жодних втрат для ефективності її роботи, але навіть з помітним виграшем.
Важливо також відзначити, що у попередній програмі розмір рядків не задається. Об'єкти типу string автоматично отримують розмір, потрібний для зберігання заданого рядка. Таким чином, у процесі виконання операцій присвоєння або конкатенації рядків рядок-прнймач збільшиться у довжину настільки, наскільки це необхідно для зберігання нового вмісту рядка. Під час оброблення string- об'єктів неможливо вийти за межі рядка. Саме цей динамічний аспект string- об'єктів вигідно відрізняє їх від рядків, що мають завершальний нуль-символ (які часто страждають від порушення меж).
Огляд функцій-членів класу string
Якщо найпростіші операції з рядками можна реалізувати за допомогою операторів, то у процесі виконання дещо складніших операцій не можливо обійтися без функцій-членів класу string. Клас string містить дуже багато функцій-членів, ми ж розглянемо тут тільки найпоширеніші з поміж них.
Нео! хідноапам ятати'.аОскільки клас String- контейнер, він підтримує такі звичайні контейнерні функції, як begin(), end() і sizeQ.
Основні маніпуляції над рядками. Щоб присвоїти один рядок іншому, найчастіше використовують функцію assign(). Ось як виглядають два можливі формати її реалізації:
string &assign(const string &strob, size_type start sizetype num)]
string &assign(const char *str. size_type num);
Перший формат дає змогу присвоїти викликуваному об'єкту пит символів з рядка, який задано параметром strob, починаючи з індексу start. Під час використання другого формату викликуваного об'єкта присвоюються перші пит символів рядка, який завершується нульовим символом, які задаються параметром sfr. У кожному випадку повертається посилання на викликуваний об'єкт. Звичайно, набагато простіше для присвоєння одного повного рядка іншому використовувати оператор присвоєння Про функцію-члена assign() згадують, в основному, тоді, коли потрібно присвоїти тільки частину рядка.
За допомогою функції-члена класу append() можна частину одного рядка приєднати до кінця іншого. Два можливі формати її реалізації мають такий вигляд:
string &append(const string &strob. size_type start size_type num)]
string &append(const char*sfr, size_type num)]
У цих записах при використанні першого формату пит символів з рядка, який задано параметром strob, починаючи з індексу start, буде приєднано до кінця викликуваного об'єкта. Другий формат дає змогу приєднати до кінця викликуваного об'єкта, перші пит символів рядка, який завершується нульовим символом, який задається параметром sfr. У кожному випадку повертається посилання на викликуваний об'єкт. Звичайно, набагато простіше для приєднання одного повного рядка до кінця іншого використовувати оператор конкатенації "+". Функція ж append() застосовується тоді, коли необхідно приєднати до кінця викликуваного об'єкта, тільки частину рядка.
Вставлення або заміну символів у рядку можна виконувати за допомогою функцій-членів класу insert() і replace(). Ось як виглядають прототипи їх найбільш використовуваних форматів:
string &insert(size_type start, const string &sfrob);
string &insert(size_type start, const string &strob, size_type insStart, size_type num);
string &replace(size_type start, size_type num, const string &sfrob);
string &replace(size_type start, size_type orgNum, const string &strob, size_type replaceStart, size_type replaceNum)',
Перший формат функції insert() дає змогу вставити рядок, який задається параметром strob, у позицію викликуваного рядка, який задано параметром start. Другий формат функції insert() призначений для вставлення пит символів з рядка, який задано параметром strob, починаючи з індексу insStart, у позицію викликуваного рядка, який задано параметром start.
Перший формат функції replaceO слугує для заміни пит символів у викликуваному рядку, починаючи з індексу start, рядком, який задано параметром strob. Другий формат дає змогу замінити orgNum символів у викликуваному рядку, починаючи з індексу start, replaceNum символами рядка, який задано параметром strob, починаючи з індексу replaceStart. У кожному випадку повертається посилання на викликуваний об'єкт.
Видалити символи з рядка можна за допомогою функції erase(). Один з її форматів має такий вигляд:
string &erase(size_type start = 0 size_type num = npos);
Ця функція видаляє num символів із викликуваного рядка, починаючи з індексу start. Функція повертає посилання на викликуваний об'єкт.
Використання функцій insertO, eraseO і replace() продемонстровано у наведеному нижче коді програми.
Код програми 12.18. Демонстрація механізму використання функцій insert(), eraseQ і replaceO
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio> // Для консольного режиму роботи
#include <string> // Для роботи з рядковими типами
using namespace std; // Використання стандартного простору імен
int mainO
{
string strl ("Це простий тест.");
string str2 С'ABC D EF G");
cout«"Початкові рядки:"« endl;
cout«"strl:"« strl « endl;
cout«"str2:"« str2 « endl« endl;
// Демонструємо механізм використання функції insertO- cout«"Вставляємо рядок str2 у рядок strl:"« endl; strl insert(5, str2); cout« strl « endl« endl;
// Демонструємо механізм використання функції eraseQ.
cout«"Видаляємо 7 символів з рядка strl« endl;
strl ,erase(5,7);
cout« strl «endl« endl;
// Демонструємо механізм використання функції replaceO- cout«"Замінюємо 2 символи в strl рядком str2:"« endl; strl replace(5,2, str2); cout« strl « endl;
getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати: Початкові рядки: strl: Це простий тест. str2: ABCDEFG
Вставляємо рядок str2 у рядок strl:
Це пАВСОЕРСростий тест.
Видаляємо 7 символів з рядка strl:
Це простий тест.
Замінюємо 2 символи в strl рядком str2:
Це пАВСОЕРСстий тест.
Пошук у рядку. У класі string передбачено декілька функцій-членів класу, які здійснюють пошук. Це, наприклад, такі функції, як find() і rfind(). Розглянемо прототипи найбільш використовуваних версій цих функцій: size_type find(const string &strob, size_type start = 0) const;
size_type rfind(const string &strob, size_type start = npos) const;
Функція findO, починаючи з позиції start, проглядає викликуваний рядок на предмет пошуку першого входження рядка, який задано параметром strob. Якщо пошук відбувся успішно, то функція findO повертає індекс, за яким у викликуваному рядку було виявлено збіг. Якщо збігу не виявлено, то повертається значення npos. Функція rfindO здійснює ту ж саму дію, але з кінця. Починаючи з позиції start, вона проглядає викликуваний рядок у зворотному порядку на предмет пошуку першого входження рядка, який задано параметром strob (тобто вона знаходить у викликуваному рядку останнє входження рядка, який задано параметром strob). Якщо пошук відбувся вдало, то функція findO повертає індекс, за яким у викликуваному рядку був виявлений збіг. Якщо збігу не виявлено, то повертається значення npos.
Розглянемо короткий приклад використання функції findO-
Код програми 12.19. Демонстрація механізму використання функції find()
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio> // Для консольного режиму роботи
#include <string> // Для роботи з рядковими типами
using namespace std; // Використання стандартного простору імен
int mainO
{
int c;
string s1 = "Клас string полегшує оброблення рядків.";
string s2;
c = s1 findf string");
if(c != string::npos) {
cout«"Збіг виявлений у позиції"« с « endl; cout«"Залишок рядка такий:"; s2.assign(s1, с, s1 .sizeO); cout« s2;
}
getchO; return 0;
}
Внаслідок виконання ця програма відображає на екрані такі результати:
Збіг виявлений у позиції 6
Залишок рядка такий: string полегшує оброблення рядків.
Порівняння рядків. Щоб порівняти повний вміст одного string-об'єкта з іншим, зазвичай використовуються описані вище перевизначені оператори відношення. Але, якщо потрібно порівняти частину одного рядка з іншим, Вам доведеться використовувати функцію-члена compare():
int compare(size_type start sizejype num, const string &strob) const;
Функція compare() порівнює із викликуваним рядком пит символів рядка, який задано параметром strob, починаючи з індексу start. Якщо викликуваний рядок менший від рядка strob, то функція compare() поверне негативне значення. Якщо викликуваний рядок більший від рядка strob, то вона поверне позитивне значення. Якщо рядок strob дорівнює викликуваному рядку, то функція compare() поверне нуль.
Отримання рядка, який завершується нульовим символом. Незважаючи на незаперечну корисність об'єктів типу string, можливі ситуації, коли Вам доведеться отримувати з такого об'єкта символьний масив, який завершується нулем, тобто його версію С-рядка. Наприклад, Ви могли б використовувати string-об'єкт для створення імені файлу. Але, відкриваючи файл, Вам потрібно задати покажчик на стандартний рядок, який завершується нульовим символом. Для вирішення цього питання і використовується функція-член c_str(). Її прототип має такий вигляд:
const char*c_str() const;
Ця функція повертає покажчик на С-версію рядка (тобто на рядок, який завершується нульовим символом), який міститься у викликуваному об'єкті типу string. Отриманий рядок, який завершується нульовим символом, зміні не підлягає. Окрім цього, після виконання інших операцій над цим string-об'єктом допустимість застосування отриманого С-рядка не гарантується.
Зберігання рядків у інших контейнерах
Оскільки клас string визначає тип даних, то можна створити контейнери, які міститимуть об'єкти типу string. Розглянемо, наприклад, вдаліший варіант програ- ми-словника, яку було показано вище.
Код програми 12.20. Демонстрація механізму використання відображення string-об'єктів для створення словника
#include <vcl>
#include <iostream> // Для потокового введення-виведення
#include <conio> // Для консольного режиму роботи
#include <map> // Для роботи з асоціативними контейнерами
#include <string> // Для роботи з рядковими типами
using namespace std; // Використання стандартного простору імен