6.9 Класс String

Вот довольно реалистичный пример класса строк string. В нем производится учет ссылок на строку с целью минимизировать копирование и в качестве констант применяются стандартные символьные строки С++.

#include «stream.h» #include «string.h»

class string (* struct srep (* char* s; // указатель на данные int n; // счетчик ссылок *); srep *p;

public: string(char *); // string x = «abc» string(); // string x; string(string amp;); // string x = string ... string amp; operator=(char *); string amp; operator=(string amp;); ~string(); char amp; operator[](int i);

friend ostream amp; operator«„(ostream amp;, string amp;); friend istream amp; operator“»(istream amp;, string amp;);


friend int operator==(string amp; x, char* s) (*return strcmp(x.p-»s, s) == 0; *)

friend int operator==(string amp; x, string amp; y) (*return strcmp(x.p-»s, y.p-»s) == 0; *)

friend int operator!=(string amp; x, char* s) (*return strcmp(x.p-»s, s) != 0; *)

friend int operator!=(string amp; x, string amp; y) (*return strcmp(x.p-»s, y.p-»s) != 0; *)

*);

Конструкторы и деструкторы просты (как обычно):

string::string() (* p = new srep; p-»s = 0; p-»n = 1; *)

string::string(char* s) (* p = new srep; p-»s = new char[ strlen(s)+1 ]; strcpy(p-»s, s); p-»n = 1; *)

string::string(string amp; x) (* x.p-»n++; p = x.p; *)

string::~string() (* if (–p-»n == 0) (* delete p-»s; delete p; *) *)

Как обычно, операции присваивания очень похожи на контрукторы. Они должны обрабатывать очистку своего первого (лвого) операнда:

string amp; string::operator=(char* s) (* if (p-»n » 1) (* // разъединить себя p-»n–; p = new srep; *) else if (p-»n == 1) delete p-»s;

p-»s = new char[ strlen(s)+1 ]; strcpy(p-»s, s); p-»n = 1; return *this; *)

Благоразумно обеспечить, чтобы присваивание объекта смому себе работало правильно:


string amp; string::operator=(string amp; x) (* x.p-»n++; if (–p-»n == 0) (* delete p-»s; delete p; *) p = x.p; return *this; *)

Операция вывода задумана так, чтобы продемонстрировать применение учета ссылок. Она повторяет каждую вводимую строку (с помощью операции ««, которая определяется позднее):

ostream amp; operator«„(ostream amp; s, string amp; x) (* return s „„ x.p-“s „« « [“ «« x.p-“n «« «]\n“; *)

Операция ввода использует стандартную функцию ввода сивольной строки (#8.4.1).

istream amp; operator»»(istream amp; s, string amp; x) (* char buf[256]; s »» buf; x = buf; cout «„ "echo: " «« x «« «\n“; return s; *)

Для доступа к отдельным символам предоставлена операция индексирования. Осуществляется проверка индекса:

void error(char* p) (* cerr «„ p «« «\n“; exit(1); *)

char amp; string::operator[](int i) (* if (i«0 !! strlen(p-»s)«i) error(„индекс за границами“); return p-»s[i]; *)

Головная программа просто немного опробует действия над строками. Она читает слова со ввода в строки, а потом эти строки печатает. Она продолжает это делать до тех пор, пока не распознает строку done, которая завершает сохранение слов в строках, или пока не встретит конец файла. После этого она печатает строки в обратном порядке и завершается.

main() (* string x[100]; int n;

cout «„ „отсюда начнем\n“; for (n = 0; cin“»x[n]; n++) (* string y; if (n==100) error(«слишком много строк»); cout «„ (y = x[n]); if (y=="done") break; *) cout «« «отсюда мы пройдем обратно\n“;

for (int i=n-1; 0«=i; i–) cout «« x[i]; *)