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

7.11 Строковый класс

Теперь можно привести более осмысленный вариант класса string.

В нем подсчитывается число ссылок на строку, чтобы минимизировать

копирование, и используются как константы стандартные строки C++.

#include <iostream.h>

#include <string.h>

class string {

struct srep {

char* s; // указатель на строку

int n; // счетчик числа ссылок

srep() { n = 1; }

};

srep *p;

public:

string(const char *); // string x = "abc"

string(); // string x;

string(const string &); // string x = string ...

string& operator=(const char *);

string& operator=(const string &);

~string();

char& operator[](int i);

friend ostream& operator<<(ostream&, const string&);

friend istream& operator>>(istream&, string&);

friend int operator==(const string &x, const char *s)

{ return strcmp(x.p->s,s) == 0; }

friend int operator==(const string &x, const string &y)

{ return strcmp(x.p->s,y.p->s) == 0; }

friend int operator!=(const string &x, const char *s)

{ return strcmp(x.p->s,s) != 0; }

friend int operator!=(const string &x, const string &y)

{ return strcmp(x.p->s,y.p->s) != 0; }

};

Конструкторы и деструкторы тривиальны:

string::string()

{

p = new srep;

p->s = 0;

}

string::string(const string& x)

{

x.p->n++;

p = x.p;

}

string::string(const char* s)

{

p = new srep;

p->s = new char[ strlen(s)+1 ];

strcpy(p->s, s);

}

string::~string()

{

if (--p->n == 0) {

delete[] p->s;

delete p;

}

}

Как и всегда операции присваивания похожи на конструкторы. В них

нужно позаботиться об удалении первого операнда, задающего левую

часть присваивания:

string& string::operator=(const char* s)

{

if (p->n > 1) { // отсоединяемся от старой строки

p->n--;

p = new srep;

}

else // освобождаем строку со старым значением

delete[] p->s;

p->s = new char[ strlen(s)+1 ];

strcpy(p->s, s);

return *this;

}

string& string::operator=(const string& x)

{

x.p->n++; // защита от случая ``st = st''

if (--p->n == 0) {

delete[] p->s;

delete p

}

p = x.p;

return *this;

}

Операция вывода показывает как используется счетчик числа ссылок.

Она сопровождает как эхо каждую введенную строку (ввод происходит

с помощью операции << , приведенной ниже):

ostream& operator<<(ostream& s, const string& x)

{

return s << x.p->s << " [" << x.p->n << "]\n";

}

Операция ввода происходит с помощью стандартной функции ввода

символьной строки ($$10.3.1):

istream& operator>>(istream& s, string& x)

{

char buf[256];

s >> buf; // ненадежно: возможно переполнение buf

// правильное решение см. в $$10.3.1

x = buf;

cout << "echo: " << x << '\n';

return s;

}

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

Индекс контролируется:

void error(const char* p)

{

cerr << p << '\n';

exit(1);

}

char& string::operator[](int i)

{

if (i<0 || strlen(p->s)<i) error("недопустимое значение индекса");

return p->s[i];

}

В основной программе просто даны несколько примеров применения

строковых операций. Слова из входного потока читаются в строки,

а затем строки печатаются. Это продолжается до тех пор, пока не

будет обнаружена строка done, или закончатся строки для записи

слов, или закончится входной поток. Затем печатаются все строки

в обратном порядке и программа завершается.

int main()

{

string x[100];

int n;

cout << " здесь начало \n";

for ( n = 0; cin>>x[n]; n++) {

if (n==100) {

error("слишком много слов");

return 99;

}

string y;

cout << (y = x[n]);

if (y == "done") break;

}

cout << "теперь мы идем по словам в обратном порядке \n";

for (int i=n-1; 0<=i; i--) cout << x[i];

return 0;

}

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]