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;
           }

Назад  |  Вперёд


OtDiatlovaOU
К началу книги

Оформление и дизайн книги OtDiatlovaOU.
Вся книга, архив.