Розробка власного класу STRING — страница 5
Обновлено
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) | char&TPString:: operator [] (int index) const char &TPString:: operator [] (int index) const { if ( (index<0) || (index>=len)) { FatalError (); } return symb [index]; } |
(1) даємо посилання на відповідний до індексу символ для того, щоб у нього можна було записати необхідну інформацію. Але недоліком є те, що замість присвоєння символу, ми можемо за посиланням зберегти адресу цього символа, а це може викликати помилки в роботі. Для недопущення цієї помилки використовуємо другу операцію індексації (7), котра повертає константний символ і, до того ж, є константною.
У разі спроби прочитати/записати символ за неіснуючим індексом, программа викликає функцію FatalError (), котра завершить виконання.
Перевантаження оператора писвоєння є аналогічною до конструктора копіювання, за виключенням того,що вона повертає вказівник на об'єкт, котрому присвоюється значення. Це дає можливість наступного коду:
TPString a,b,c;
· · ·
a = b = c;
Операцій додавання рядків, або конкатенація реалізовані наступним чином:
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) | TPString &TPString:: operator+= (const TPString& part) { if (BuffLen< (len+1+part. len)) { BuffLen=len+1+part. len; char *ptr=new char [BuffLen]; strcpy (ptr,symb); strcpy (ptr+len,part. symb); ptr [BuffLen-1] =0; delete [] symb; symb=ptr; } else { strcpy (symb+len,part. symb); } len+=part. len; return *this; } TPString &TPString:: operator+ (const TPString& part) { TPString temp (*this); temp+=part; return temp; } |
В (1) об'являється оператор += котрий і виконує конкатенацію. Параметром є посилання на об'єкт типу TPString. сonst гарантує незмінність об'єкту. (3) перевірка на достатність виділеної пам'яті для розміщення рядка. (4) обчислення необхідго розміру буферу. (5) видіеня необхідної пам'яті. (6) та (7) копіювання рядків до нового буферу. (8) встановлення символу кінця рядка. (9) знищення старого буферу.
Оператор + загалом об'влений у (18) також має константний параметр. У (20) створюється тимчасовий об'єкт на основі існуючого. Далі виклик += і повернення результату. Завдяки первантаженню операції = уникаємо помлок копіювання.
Функція Clear () присвоює значення рядку “”
void TPString:: Clear ()
{
len=0;
if (symb! =NULL) symb [0] ='\0';
}
Функція видалення певної кількості символів приймає два параметра: стартова позиція та кількість символів.
(1) (2) (3) (4) (5) (6) (7) (8) | void TPString:: TPdelete (int startpos, int count) count<0) return; if (startpos+count>=len |
Алгоритм видалення досить простий: символи з кінця рядка переписуються замість тих, що підлягають видаленню (6). Перевірки (3) та (4) реалізують коректність роботи алгоритму.
Алгоритм вставки рядка в рядок є більш складним, але подібний до операції інкременту.
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) | void TPString:: insert (TPString& part, int pos, int count) { if (pos>len) return; if (count>part. len) count=part. len; if (part. len<count||count<=0) count=part. len; if (BuffLen>=len+count+1) { for (int i=len; i>=pos; - -i) { symb [i+count] =symb [i]; } for (int i=0; i<count; i++, pos++) { symb [pos] =part. symb [i]; } } else { char *temp=new char [len+part. len+1]; strncpy (temp,symb,pos); strncpy (temp,part. symb,count); strncpy (temp,symb+pos,len-pos); delete [] symb; symb=temp; BuffLen=len+part. len+1; } len+=count; } |
Рядки (3) - (5) реалізують коректність роботи алгоритму. У рядках (7) - (24) реалізований алгоритм конкатенації, оснований на попередньому "роздвиганні" базового рядка у який виконується ставка. У (26) ми встановлюємо поточну довжину рядка.
Захищена функція
void TPString:: setString (const char* s)
{
if (BuffLen<len+1)
{
if (symb! =NULL) delete [] symb;
BuffLen=len+1;
symb=new char [BuffLen];
}
strcpy (symb,s);
}
виконує виділення необхідного об'єму буферу та копіювання у нього нове значення.
Об'ява нащадку TPStrThread від TPString має наступний вигляд:
class TPStrThread abstract: virtual public TPString
{
···
}
Ключове слово abstract говорить про те, що об'єкти класу неможна створювати, проте ми додали конструктор, що ініціалізуватиме у подальшому усю систему.
Головною відмінністю є наявність двох дружніх функцій, що є перевантаженням операцій введення/виведення.
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28) (29) (30) (31) | ostream &operator<< (ostream& out, const TPStrThread& tp) { for (int i=0; i<tp. len; i++) out<<tp. symb [i]; return out; } istream &operator>> (istream& input, TPStrThread& tp) { int i=256; int k=-1; char *temp=new char [i]; do{ k++; if (k>i) { i<<1; char * t=new char [i]; strncpy (t,temp,k); delete [] temp; temp=t; } input. get (temp [k]); }while (temp [k] ! ='\n'); temp [k] =0; if (tp. symb! =NULL) delete [] tp. symb; tp. symb=temp; tp. BuffLen=i; tp. len=strlen (temp); return input; } |
У рядку (1) перевантажується операція виведення, вона подібна до операції виведення рядка у стилі С. (5) повертає посилання на потік, що дозволяє виконувати наступну операцію:
cout << … << …;
Операція введення (8) реалізована на основі динамічного алгоритму: виділяється буфер, якщо не вистачає, то виділяється у два рази більший (у нього копіюється попередній і звільняється) і т.д. Замість множення на 2 використовуюємо швидшу операцію зсуву. Це дозволяє максимально збалансувати швидкість виконання та використання ресурсів.
Об'ява нащадку TPStrCompare від TPString має наступний вигляд:
class TPStrCompare abstract: virtual public TPString
{···}
У ньому ми перевантажимо всі операції порівняння:
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21) (22) (23) (24) (25) (26) (27) (28) (29) | bool TPStrCompare:: operator! () const { if (len==0) return true; else return false; } bool TPStrCompare:: operator! = (const TPStrCompare& part) const { return (strcmp (symb,part. symb) ! =0); } bool TPStrCompare:: operator== (const TPStrCompare& part) const { return! (*this! = part); } bool TPStrCompare:: operator< (const TPStrCompare& part) const { return strcmp (symb,part. symb) <0; } bool TPStrCompare:: operator> (const TPStrCompare& part) const { return (strcmp (symb,part. symb) >0); } bool TPStrCompare:: operator<= (const TPStrCompare& part) const { return! (*this> part); } bool TPStrCompare:: operator>= (const TPStrCompare& part) const { return! (*this< part); } |
У рядках (1), (6), (10), (14), (16), (18), (22), (26) об'являються оператори порівнняння. Кожен з них є константною функцією та приймає константні аргументи, що гарантує захищеність, та щожливість використання, коли об'єкт був об'явлений константно.
У рядках (16) та (20) викорисовубться функіії порівняння у стилі С. Останні функції порівняння (крім (1)) створювалися на основі заданих.
Розробка результуючого класу пов'язана з успадкуванням від двох абстрактних. Має наступну об'яву:
class clsString: public TPStrThread, public TPStrCompare
{ ··· }
Зауважимо, що базові класи не є віртуальними і немає наслідування від базового класу (як це зазначено у теоретичній частині). Виклики конструкторів будуть проходити так:
Конструктор за замовчуванням TPString
Конструктор за замовчуванням TPStrThread або TPStrCompare
Конструктор за замовчуванням TPStrCompare або TPStrThread
Конструктор clsString
Пункти 2 і 3 рівносильні і їх порядок залежить від компілятору (хоча в стандарті сказано, що вони викликаються в порядку об'яви).
В звязку з тим, що конструктори та операції присвоєння не наслідубться потрібно їх створювати зоново. Конструктори копіювання та перетворення аналогічні TPString. Розглянемо добавлені конструктори.
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) | clsString:: clsString (const long l) { char s [_CVTBUFSIZE]; if (_i64toa_s (l,s,15,10) ==EINVAL) code=1; else code=0; len=strlen (s); BuffLen=0; symb=NULL; setString (s); } clsString:: clsString (const double d, int pers) { char buf [_CVTBUFSIZE]; if (_gcvt (d,pers,buf) ! =0) code=1; else code=0; len=strlen (buf); BuffLen=0; symb=NULL; setString (buf); } |
У рядках (1) та (11) також об'явлені конструктори перетворення.
Цікавим є виділення пам'яті для тимчасового буферу, використовуючи _CVTBUFSIZE.
Згідно документації вона забезпечує саме той розмір, який необхідно для розміщення будь-якого число у строковому форматі, не залежно від системи (3) та (13).
Функція i64toa_s (4) забезпечує перетворення 64 бітного цілого на строку і у разі помилки повертає EINVAL.
Функція _gcvt (14) перетворює дійсне число у рідок символів і у разі помилки повертає її значення. (6) - (9) та (15) - (18) аналогічні розлянутим раніше.
Оператор () повертає підстроку але за типом класу:
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) | clsString& clsString:: operator () (int index, int subLen) index+subLen>=len) return clsString (""); char *tempstr=new char [subLen+1]; if (subLen==0) subLen=len-index; strncpy (tempstr,symb+index,subLen); tempstr [subLen] ='\0'; clsString temp (tempstr); delete [] tempstr; return temp; |
У (3) забзпечення коректності роботи алгоритму. (4) виділення тимчасовогу буферу.
У рядку (6) - копіювання підрядка, котрий у (8) передається у якості аргументу.
Далі (9) знищення тимчасового буферу та (10) повертання результату.
Функція пошуку першого входження реалізована за надійним але не найшвидшим алгоритмом О (n) =n*m, n-довжина базового рядка, а m-довжина рядка еквівалент якого шукаємо.
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) | int clsString:: find (const clsString& comp, int pos) { bool Notequal=1; if (comp. len>pos+this->len) return - 1; int fin=this->len-comp. len; for (; (pos<=fin) &&Notequal; pos++) { int k=0; for (int j=pos; k<comp. len; k++,j++) if (this->symb [j] ! =comp. symb [k]) break; if (k==comp. len) Notequal=0; } if (Notequal) return - 1; else return pos; } |
Флагова змінна Notequal (3) слугує для визначення: чи було знайдене вхождения. Змінна fin (5) вказує на кількість символім починаючи з яких необхідно виконати порівняння. (10) вийти з вложенного циклу, якщо знайдені неодинакові символи.
2.3 ТестуванняРезультат проведення тестування:(Т1) (Т2) (Т3) (Т4) (Т5) (Т6) (Т7) (Т8) (Т9) (Т10) (Т11) (Т12) (Т13) (Т14) (Т15) (Т16) (Т17) (Т18) (Т19) (Т20) (Т21) (Т22) (Т23) (Т24) (Т25) (Т26) (Т27) (Т28) (Т29) (Т30) (Т31) (Т32) (Т33) (Т34) (Т35) (Т36) (Т37) (Т38) (Т39) | This program will test my work This is a small driver Testing in process This is a small driver Enter string Enter string Good day! This is a very good day! I have already done my work! Good day! This is a very good day! I have already done my work! s1 is "Testing in process" and s2 is "This is a small driver" The results of comparing is: s2==s1 yields false s2! =s1 yields true s2>s1 yields true s2<s1 yields false s2<=s1 yields false s2>=s1 yields true s1 += s2 yields s1 = Testing in processThis is a small driver s1 after s1 [0] = 't' and s1 [1] ='E' tEsting in processThis is a small driver find and delete in s1 s2 tEsting in process ********************************************************** s1 is "112211221122" and s2 is "334433443344334"Insert to s1 5 symbols from s2. Start position 0: 33443112211221122 Insert to s1 5 symbols from s2. Start position 5: 11221334431221122 Insert to s1 5 symbols from s2. Start position end of s1: 11221122112233443 2007 12.3456789012 Для продолжения нажмите любую клавишу... |
Тестування об'яви змінних, тобто конструкторів:
(1) (2) (3) (4) (5) (6) (7) | clsString* temp=new clsString ("This program will test my work"); cout <<*temp<<endl; *temp= (clsString)"This is a small driver"; clsString test1 ("Testing in process"); clsString test2; clsString test3 (*temp); cout<<*temp<<endl<<test1<<endl<<test2<<endl<<test3; |
Создамо динамічний об'єкт (1) присвоївши значення "This program will test my work". Буде викликаний конструктор преведення типів. Перевіримо отримане значення (2), вивівши його в потік (чим і почнемо тестуваня введення/виведення). Далі виконаємо явне приведення типів (3), а також перевіримо оператор присвоєння. Крім того в покроковому режимі перевіримо роботу деструктора. Варіант створення статичної змінної (4) з початковим значенням, а із значенням за замовчуванням (5). Створення об'єкту на основі конструктора копіювання у рядку (6). Створені об'єкти у рядках (3) - (6) виведемо в потік (7). Результати роботи рядкі (1) - (7) є рядки на єкрані (Т1) - (Т5).
Далі протестуємо оператор введення.
(1) (2) (3) (4) (5) (6) | cout<<"\nEnter string"<<endl; cin>>test2; cout<<test2<<endl; cout<<"Enter string"<<endl; cin>>test2; cout<<test2<<endl; |
У рядках (1) та (3) попросимо ввести рядок символів, що закінчується оператором переходу на новий рядок. Далі (2) та (4) вводимо ці рядки, та відразу ж показуємо введене. Має сенс ввести порожню строку, а потім непорожню. Результати у рядках (6) - (11).
Протестуємо оператори порівняння:
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) | cout<<"\ns1 is \""<<test1<<"\" and s2 is \""<< test3<<"\"" <<"\n\nThe results of comparing is: " <<"\ns2==s1 yields " << (test3==test1?"true": "false") <<"\ns2! =s1 yields " << (test3! =test1?"true": "false") <<"\ns2>s1 yields " << (test3>test1?"true": "false") <<"\ns2<s1 yields " << (test3<test1?"true": "false") <<"\ns2<=s1 yields " << (test3<=test1?"true": "false") <<"\ns2>=s1 yields " << (test3>=test1?"true": "false") <<endl; |
У рядку (1) вказуємо дві строки, які ми будемо порівнювати. У рядках (3), (5), (7), (9), (11), (13) ми говоримо користувачу, яку операцію будемо тестувати, а у наступномі виводимо результат відповідного тестування, використовуючи тернарну операцію. Результати (Т12) - (Т20).
Наступним етапом тестування стане операція конкатенації, процес її тестування подібний до операції тестування (Т23):
cout << "\n\ns1 += s2 yields s1 = ";
test1 += test3; // test overloaded concatenation
cout << test1<<endl;
Операція індексації матиме 2 тести: зміна 0 символу (відлік символів починається з 0), будь-якого іншого, наприклад 1, бо вказівник на рядок-вказівник на перший символ, а далі перевірка операції індексації (Т24) - (Т25):
test1 [0] ='t';
test1 [1] ='E';
cout<<"s1 after s1 [0] = 't' and s1 [1] ='E'"<<endl;
cout<<test1<<endl;
Функцію пошуку об'єднаємо з функцією видалення рядка:
(1) (2) (3) | int pos=test1. find (test3); test1. TPdelete (pos,test3. lenght ()); cout<<test1<<endl; |
У змінну pos отримаємо позицію входження, потім (2) з цієї позиції видалимо весь рядок test3, використовуючи функцію визначення довжини рядка. Та виведемо (3) результат видалення (Т26) - (Т27).
Тестування операцій вставки більш складне:
(1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) | test1="112211221122"; test3="334433443344334"; cout<<"\ns1 is \""<<test1<<"\" and s2 is \""<< test3<<"\""; cout<<"Insert to s1 5 symbols from s2. Start position 0: "<<endl; test1. insert (test3,0,5); cout<<test1<<endl; test1="112211221122"; test3="334433443344334"; cout<<"Insert to s1 5 symbols from s2. Start position 5: "<<endl; test1. insert (test3,5,5); cout<<test1<<endl; test1="112211221122"; test3="334433443344334"; cout<<"Insert to s1 5 symbols from s2. Start position end of s1: "<<endl; test1. insert (test3,test1. lenght (),5); cout<<test1<<endl; |
Для полегшення перевірки вставки задамо початкові строки (1) - (2), (7) - (8), та (12) - (13).
Вставка в початок рядка (5), між 5 та 6 символами (10) та в кінець (13). Результати приведені у рядках (Т30) - (Т36).
На останок тестування конструкторів перетворення з числа до строки. Так як вони основані лице на стандартних операціях строк у стилі С, достатньо одного тесту на кожний:
(1) (2) (3) (4) (5) (6) | temp=new clsString ( (long) 2007); cout<<*temp<<endl; temp->~clsString (); temp=new clsString (-12.34567890123); cout<<*temp<<endl; temp->~clsString (); |
У (1) та (4) створення об'єкту та передача значення. Замітимо явне приведення типу у (1), якщо цьго невиконати, то компілятор видасть помилку "error C2668: 'clsString:: clsString': ambiguous call to overloaded function". Це пов'язане з тим, що компілятор неявно не розрізняє ціле та дійсне числа, тому виника б неоднозначність. Ми використовуємо динамічні об'єкти, а отже виклик деструкторів (3) та (6) обов'язковий. Результат (2) та (3) є рядки (Т37) та (Т38).
ВисновкиВ ході виконання курсової роботи були отримані наступні результати.Розроблено клас clsString, який призначений для розв'язку задачі обробки рядків.Розроблений клас включає 4 компонентів-даних та 29 компонентів-методів, серед яких 2 є захищеними, 29 можуть успадковуватися, а 27 є загальнодоступними. Клас включає 4 конструктори, 1 деструктор, 1 віртуальних функцій, надає можливості з використання найменувань стандартних операцій для виконання введення/виведення в потік, порівняння рядків.Розроблений клас є похідним від класів TPStrThread та TPStrCompare, котрі є похідними від класу TPString.Особливостями розробленого класу є можливість ініціалізації, отримуючи дійсне чи ціле число, та пошук першого входження з вказаної позиції підстроки.Результати тестування підтвердили працездатність і ефективність використання об'єктів, створюваних на основі розробленого класу.Розроблене програмне забезпечення функціонує під керуванням операційної системи Windows.Література1. MSDN
2. Pohl, Ira C++ by Dissection. Addison-Winsley: New York, 2002.520p
3. Stroustrup, Bjarne The C++ Programing Language. Addison-Winsley: New York, 1997.912p
4. Дейтел Х.М. Дейтел П. Дж. Как программировать на С++. М.: Бином, 2005.1244с
5. Липпман С.Б. С++ для начинающих. М.: Питер, 2002.1194с
ДодаткиДодаток А
Код файлу "TPstr. h", з об'явою класів.
#ifndef TPSTR_H
#define TPSTR_H
#include <iostream>
using std:: ostream;
using std:: istream;
class TPString
{
public:
// TPString ();
TPString (const char * = "");
TPString (TPString&);
~TPString ();
char&operator [] (int);
const char &operator [] (int) const;
TPString &operator= (TPString&);
TPString &operator+= (const TPString&);
TPString &operator+ (const TPString&);
void Clear ();
void TPdelete (int startpos, int count);
void insert (TPString&, int pos, int count);
int lenght () const;
virtual int ErrorCode () {return 0; }
protected:
int BuffLen;
int len;
char * symb;
void FatalError () const;
void setString (const char*);
};
class TPStrThread abstract: virtual public TPString
{
friend ostream &operator<< (ostream&, const TPStrThread&);
friend istream &operator>> (istream&, TPStrThread&);
public:
char* GetStr (); // повертає копію рядка у стилі С
char* GetStr (int stpos, int count); // копія підрядка у стилі С
};
class TPStrCompare abstract: virtual public TPString
{
public:
bool operator! () const; // Чи порожня строка
bool operator! = (const TPStrCompare&) const;
bool operator== (const TPStrCompare&) const;
bool operator< (const TPStrCompare&) const;
bool operator> (const TPStrCompare&) const;
bool operator<= (const TPStrCompare&) const;
bool operator>= (const TPStrCompare&) const;
};
class clsString: public TPStrThread, public TPStrCompare
{
public:
clsString (const char * = "");
clsString (const long);
clsString (const double, int pers = 12);
clsString (clsString&);
~clsString () {}
clsString &operator () (int, int);
clsString & operator= (const clsString&);
int ErrorCode () {return code; }
int find (const clsString&, int pos =0);
private:
int code;
};
#endif
Додаток Б
Код файлу "TPstr. cpp", з описом методів класів.
#include "TPstr. h"
#include <errno. h>
// class TPString
TPString:: TPString (const char *s)
{
len=strlen (s);
BuffLen=0;
symb=NULL;
setString (s);
}
TPString:: TPString (TPString & copy)
{
len=copy. len;
BuffLen=0;
symb=NULL;
setString (copy. symb);
}
TPString:: ~TPString ()
{
delete [] symb;
}
char&TPString:: operator [] (int index)
const char &TPString:: operator [] (int index) const
{
if ( (index<0) || (index>=len))
{
FatalError ();
}
return symb [index];
}
TPString &TPString:: operator= (TPString& copy)
{
len=copy. len;
setString (copy. symb);
return *this;
}
TPString &TPString:: operator+= (const TPString& part)
{
if (BuffLen< (len+1+part. len)) {
BuffLen=len+1+part. len;
char *ptr=new char [BuffLen];
strcpy (ptr,symb);
strcpy (ptr+len,part. symb);
ptr [BuffLen-1] =0;
delete [] symb;
symb=ptr;
} else {
strcpy (symb+len,part. symb);
}
len+=part. len;
return *this;
}
TPString &TPString:: operator+ (const TPString& part)
{
TPString temp (*this);
temp+=part;
return temp;
}
void TPString:: Clear ()
{
len=0;
if (symb! =NULL) symb [0] ='\0';
}
void TPString:: TPdelete (int startpos, int count)
void TPString:: insert (TPString& part, int pos, int count)
{
if (pos>len) return;
if (count>part. len) count=part. len;
if (part. len<count||count<=0) count=part. len;
if (BuffLen>=len+count+1) {
for (int i=len; i>=pos; - -i)
{
symb [i+count] =symb [i];
}
for (int i=0; i<count; i++, pos++)
{
symb [pos] =part. symb [i];
}
// symb [pos] ='\0';
} else {
char *temp=new char [len+part. len+1];
strncpy (temp,symb,pos);
strncpy (temp,part. symb,count);
strncpy (temp,symb+pos,len-pos);
delete [] symb;
symb=temp;
BuffLen=len+part. len+1;
}
len+=count;
}
int TPString:: lenght () const
{
return len;
}
void TPString:: setString (const char* s)
{
if (BuffLen<len+1)
{
if (symb! =NULL) delete [] symb;
BuffLen=len+1;
symb=new char [BuffLen];
}
strcpy (symb,s);
}
void TPString:: FatalError () const
{
exit (1); }
// class TPStrThread
ostream &operator<< (ostream& out, const TPStrThread& tp)
{
for (int i=0; i<tp. len; i++)
out<<tp. symb [i];
return out;
}
istream &operator>> (istream& input, TPStrThread& tp)
{
int i=256;
int k=-1;
char *temp=new char [i];
do{
k++;
if (k>i) {
i<<1;
char * t=new char [i];
strncpy (t,temp,k);
delete [] temp;
temp=t;
}
input. get (temp [k]);
}while (temp [k] ! ='\n');
temp [k] =0;
if (tp. symb! =NULL) delete [] tp. symb;
tp. symb=temp;
tp. BuffLen=i;
tp. len=strlen (temp);
return input;
}
// TPStrThread &operator= (TPStrThread&);
char* TPStrThread:: GetStr ()
{
char *temp=new char [len+1];
strcpy (temp,symb);
return temp;
}
char* TPStrThread:: GetStr (int stpos, int count)
// class TPStrCompare
bool TPStrCompare:: operator! () const
{
if (len==0) return true; else return false;
}
bool TPStrCompare:: operator! = (const TPStrCompare& part) const
{
return (strcmp (symb,part. symb) ! =0);
}
bool TPStrCompare:: operator== (const TPStrCompare& part) const
{
return! (*this! = part);
}
bool TPStrCompare:: operator< (const TPStrCompare& part) const
{
return strcmp (symb,part. symb) <0;
}
bool TPStrCompare:: operator> (const TPStrCompare& part) const
{
return (strcmp (symb,part. symb) >0);
}
bool TPStrCompare:: operator<= (const TPStrCompare& part) const
{
return! (*this> part);
}
bool TPStrCompare:: operator>= (const TPStrCompare& part) const
{
return! (*this< part);
}
// class clsString
clsString:: clsString (const char * s)
{
len=strlen (s);
BuffLen=0;
symb=NULL;
setString (s);
}
clsString:: clsString (const long l)
{
char s [_CVTBUFSIZE];
if (_i64toa_s (l,s,15,10) ==EINVAL) code=1;
else code=0;
len=strlen (s);
BuffLen=0;
symb=NULL;
setString (s);
}
clsString:: clsString (const double d, int pers)
{
char buf [_CVTBUFSIZE];
if (_gcvt (d,pers,buf) ! =0) code=1; else code=0;
len=strlen (buf);
BuffLen=0;
symb=NULL;
setString (buf);
}
clsString:: clsString (clsString& s)
{
len=s. len;
setString (s. symb);
}
clsString & clsString:: operator= (const clsString& copy)
{
len=copy. len;
setString (copy. symb);
return *this;
}
clsString& clsString:: operator () (int index, int subLen)
int clsString:: find (const clsString& comp, int pos)
{
bool Notequal=1;
if (comp. len>pos+this->len) return - 1;
int fin=this->len-comp. len;
for (; (pos<=fin) &&Notequal; pos++)
{
int k=0;
for (int j=pos; k<comp. len; k++,j++)
if (this->symb [j] ! =comp. symb [k]) break;
if (k==comp. len) Notequal=0;
}
if (Notequal) return - 1;
else return pos;
}
Додаток С
Код файлу "driver. cpp", з драйвером тестування.
#include <iostream>
#include "TPstr. h"
using namespace std;
int main ()
{
clsString* temp=new clsString ("This program will test my work");
cout <<*temp<<endl;
*temp= (clsString)"This is a small driver";
clsString test1 ("Testing in process");
clsString test2;
clsString test3 (*temp);
cout<<*temp<<endl<<test1<<endl<<test2<<endl<<test3;
cout<<"\nEnter string"<<endl;
cin>>test2;
cout<<test2<<endl;
cout<<"Enter string"<<endl;
cin>>test2;
cout<<test2<<endl;
cout<<"s1 is \""<<test1<<"\" and s2 is \""<< test3<<"\""
<<"\n\nThe results of comparing is: "
<<"\ns2==s1 yields "
<< (test3==test1?"true": "false")
<<"\ns2! =s1 yields "
<< (test3! =test1?"true": "false")
<<"\ns2>s1 yields "
<< (test3>test1?"true": "false")
<<"\ns2<s1 yields "
<< (test3<test1?"true": "false")
<<"\ns2<=s1 yields "
<< (test3<=test1?"true": "false")
<<"\ns2>=s1 yields "
<< (test3>=test1?"true": "false") <<endl;
cout << "\n\ns1 += s2 yields s1 = ";
test1 += test3; // test overloaded concatenation
cout << test1<<endl;
test1 [0] ='t';
test1 [1] ='E';
cout<<"s1 after s1 [0] = 't' and s1 [1] ='E'"<<endl;
cout<<test1<<endl;
cout<<"find and delete in s1 s2"<<endl;
int pos=test1. find (test3);
test1. TPdelete (pos,test3. lenght ());
cout<<test1<<endl;
cout<<"**********************************************************\n";
test1="112211221122";
test3="334433443344334";
cout<<"\ns1 is \""<<test1<<"\" and s2 is \""<< test3<<"\"";
cout<<"Insert to s1 5 symbols from s2. Start position 0: "<<endl;
test1. insert (test3,0,5);
cout<<test1<<endl;
test1="112211221122";
test3="334433443344334";
cout<<"Insert to s1 5 symbols from s2. Start position 5: "<<endl;
test1. insert (test3,5,5);
cout<<test1<<endl;
test1="112211221122";
test3="334433443344334";
cout<<"Insert to s1 5 symbols from s2. Start position end of s1: "<<endl;
test1. insert (test3,test1. lenght (),5);
cout<<test1<<endl;
temp->~clsString ();
temp=new clsString ( (long) 2007);
cout<<*temp<<endl;
temp->~clsString ();
temp=new clsString (-12.34567890123);
cout<<*temp<<endl;
temp->~clsString ();
return 0;
}
