Программирование >>  Поддержка объектно-ориентированного программирования 

1 ... 60 61 62 [ 63 ] 64 65 66 ... 120


указатель на строку счетчик числа ссылок

string x string x; string x

abc

string

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();

string(const 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 ;

Операция ввода происходит с помощью стандартной функции ввода символьной строки ($$1 0.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];



7.12 Друзья и члены

В заключении можно обсудить, когда при обращении в закрытую часть пользовательского типа стоит использовать функции-члены, а когда функции-друзья. Некоторые функции, например конструкторы, деструкторы и виртуальные функции ($$R.12), обязаны быть членами, но для других есть возможность выбора. Поскольку, описывая функцию как член, мы не вводим нового глобального имени, при отсутствии других доводов следует использовать функции-члены.

Рассмотрим простой класс X:

class X { ...

X(int);

int m1();

int m2() const;

friend int f1(X&);

friend int f2(const X&);

friend int f3(X);

Вначале укажем, что члены X::m1() и X::m2() можно вызывать только для объектов класса X. Преобразование X(int) не будет применяться к объекту, для которого вызваны X::m1() или X::m2():

void g()

1.m1(); ошибка: X(1).m1() не используется 1.m2(); ошибка: X(1).m2() не используется

Глобальная функция f1() имеет то же свойство ($$4.6.3), поскольку ее параметр - ссылка без спецификации const. С функциями f2() и f3() ситуация иная:

void h()

f1(1); ошибка: f1(X(1)) не используется

f2(1); нормально: f2(X(1));

f3(1); нормально: f3(X(1));

В основной программе просто даны несколько примеров применения строковых операций. Слова из входного потока читаются в строки, а затем строки печатаются. Это продолжается до тех пор, пока не будет обнаружена строка done, или закончатся строки для записи слов, или закончится входной поток. Затем печатаются все строки в обратном порядке и программа завершается.

int main()

string x[100]; int n;

cout << здесь начало \n ; for ( n = 0; cin>>x[n]; n++) {

if (n==100) {

еггог( слишком много слов ); 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;



1 ... 60 61 62 [ 63 ] 64 65 66 ... 120

© 2006 - 2024 pmbk.ru. Генерация страницы: 0.001
При копировании материалов приветствуются ссылки.
Яндекс.Метрика