25: const char * GetStnng() const { return itsStnng, }
26:
27: private:
28: Stnng (unsigned short), // Закрытый конструктор
29: char * itsStnng,
30: unsigned short itsLen
31: }
32:
33: // Конструктор, заданный no умолчанию, создает строку нулевой длины
34: String String()
35: {
36: itsStnng = new char[1]
37: itsStrmg[0] = ' '
38: itsLen=0;
39: }
40:
41: // Закрытый (вспомогательный) конструктор
42: // используется только методами класса для создания
43: // строк требуемой длины с нулевым наполнением
4й: String String(unsigned short len)
45: {
46: itsStnng = new char[len+1]
47: for (unsigned short i = 0 i<=len, i++)
48: itsString[i] = ,
49: itsLen=len,
50: }
51:
52: // Преобразование массива символов в строку
53: String String(const char * const cString)
54: {
55: itsLen = strlen(cString);
56: itsString = new char[itsLen+1];
57: for (unsigned short i = 0; i<itsLen: i++)
58: itsString[i] = cString[i];
59: itsString[itsLen]=' ';
60: }
61:
62: // Конструктор-копировщик
63: String::String (const String & rhs)
64: {
65: itsLen=rhs.GetLen();
66: itsString = new char[itsLen+1];
67: for (unsigned short i = 0; i<itsLen;i++)
68: itsString[i] = rhs[i];
69: itsString[itsLen] = ' ';
70: }
71:
72: // Деструктор для освобождения памяти
73: String::~String ()
74: {
75: delete [] itsString;
76: itsLen = 0;
77: }
78:
79: // Оператор присваивания освобождает память
80: // и копирует туда string и size
81: String& String::operator=(const String & rhs)
82: {
83: if (this == &rhs)
84: return *this;
85: delete [] itsString;
86: itsLen=rhs.GetLen();
87: itsString = new char[itsLen+1];
88: for (unsigned short i = 0; i<itsLen;i++)
89: itsString[i] = rhs[i];
90: itsString[itsLen] = ' ';
91: return *this;
92: }
93:
94: //неконстантный оператор индексирования
95: // возвращает ссылку на символ так, что его
96: // можно изменить!
97: char & String::operator[](unsigned short offset)
98: {
99: if (offset > itsLen)
100: return itsString[itsLen-1];
101: else
102: return itsString[offset];
103: }
104:
105: // константный оператор индексирования для использования
106: // с константными объектами (см. конструктор-копировщик!)
107: char String::operator[](unsigned short offset) const
108: {
109: if (offset > itsLen)
110: return itsString[itsLen-1];
111: else
112: return itsString[offset];
113: }
114:
115: // создание новой строки путем добавления
116: // текущей строки к rhs
117: String String::operator+(const String& rhs)
118: {
119: unsigned short totalLen = itsLen + rhs.GetLen();
120: String temp(totalLen);
121: unsigned short i;
122: for ( i= 0; i<itsLen; i++)
123: temp[i] = itsString[i];
124: for (unsigned short j = 0; j<rhs.GetLen(); j++, i++)
125: temp[i] = rhs[j];
126: temp[totalLen]=' ';
127: return temp;
128: }
129:
130: // изменяет текущую строку и возвращает void
131: void String::operator+=(const String& rhs)
132: {
133: unsigned short rhsLen = rhs.GetLen();
134: unsigned short totalLen = itsLen + rhsLen;
135: String temp(totalLen);
136: unsigned short i;
137: for (i = 0; i<itsLen; i++)
138: temp[i] = itsString[i];
139: for (unsigned short j = 0; j<rhs.GetLen(); j++, i++)
140: temp[i] = rhs[i-itsLen];
141: temp[totalLen]=' ';
142: *this = temp;
143: }
144:
145: int main()
146: {
147: String s1("initial test");
148: cout << "S1:t" << s1.GetString() << endl;
149:
150: char * temp = "Hello World";
151: s1 = temp;
152: cout << "S1:t" << s1.GetString() << endl;
153:
154: char tempTwo[20];
155: strcpy(tempTwo,"; nice to be here!");
156: s1 += tempTwo;
157: cout << "tempTwo:t" << tempTwo << endl;
158: cout << "S1:t" << s1.GetString() << endl;
159:
160: cout << "S1[4] :t" << s1[4] << endl;
161: s1[4]='o';
162: cout << "S1:t" << s1.GetString() << endl;
163:
164: cout << "S1[999] :t" << s1[999] << endl;
165:
166: String s2(" Another string");
167: String s3;
168: s3 = s1+s2;
169: cout << "S3:t" << s3.GetString() << endl:
170:
171: String s4;
172: s4 = "Why does this work?";
173: cout << "S4:t" << s4.GetString() << endl;
174: return 0;
175: }
Результат:
S1: initial test
S1: Hello world
tempTwo: ; nice to be here!
S1: Hello world; nice to be here!
S1[4]: o
S1: Hello World; nice to be here!
S1[999]: !
S3: Hello World; nice to be here! Another string
S4: Why does this work?
Анализ: В строках 7—31 объявляется простой класс String. В строках 11—13 объявляются конструктор по умолчанию, конструктор-копировщик и конструктор для приема существующей строки с концевым нулевым символом (стиль языка С).
В классе String перегружаются операторы индексирования ([]), суммирования (+) и присваивания с суммой (+=). Оператор индексирования перегружается дважды. Один раз как константная функция, возвращающая значение типа char, а другой — как неконстантная функция, возвращающая указатель на char.
Неконстантная версия оператора используется в выражениях вроде строки 161: SomeString[4]=V;
В результате открывается прямой доступ к любому символу строки. Поскольку возвращается ссылка на символ, функция получает доступ к символу и может изменить его.
Константная версия оператора используется в тех случаях, когда необходимо получить доступ к константному объекту класса String, например при выполнении конструктора-копировщика в строке 63. Обратите внимание, что в этом случае открывается доступ к rhs[i], хотя rhs был объявлен как const String &. К этому объекту невозможно получить доступ, используя неконстантные функции-члены. Поэтому оператор индексирования необходимо перегрузить как константный.
Если возвращаемый объект окажется слишком большим, возможно, вам потребуется установить возврат не значения, а константной ссылки на объект. Но поскольку в нашем случае один символ занимает всего один байт, в этом нет необходимости.
Конструктор, заданный по умолчанию, выполняется в строках 33—39. Он создает строку нулевой длины. Общепринято, что в классе String длина строки измеряется без учета концевого нулевого символа. Таким образом, строка, созданная по умолчанию, содержит только концевой нулевой символ.
Конструктор-копировщик выполняется в строках 63—70. Он задает длину новой строки равной длине существующей строки плюс одна ячейка для концевого нулевого символа. Затем конструктор-копировщик копирует существующую строку в новую и добавляет в конце нулевой символ окончания строки.
В строках 53—60 выполняется конструктор, принимающий строку с концевым нулевым символом. Этот конструктор подобен конструктору-копировщику. Длина существующей строки определяется с помощью стандартной функции strlen() из библиотеки String.
В строке 28 объявляется еще один конструктор, String(unsigned short), как закрытая функция-член. Он был добавлен для того, чтобы не допустить создания в классе String строк произвольной длины каким-нибудь другим пользовательским классом. Этот конструктор позволяет создавать строки только внутри класса String в соответствии со сделанными установками, как, например, в строке 131 с помощью operator+=. Более подробно этот вопрос рассматривается ниже, при объявлении operator+=.
Конструктор String(unsigned short) заполняет все элементы своего массива символов значениями NULL. Поэтому в цикле for выполняется проверка i<=len, а не i<len.
Деструктор, выполняемый в строках 73—77, удаляет строку текста, поддерживаемую классом String. Обратите внимание, что за оператором delete следуют квадратные скобки. Если опустить их, то из памяти компьютера будут удалены не все объекты класса, а только первый из них.
Оператор присваивания прежде всего определяет, не соответствуют ли друг другу операнды слева и справа. Если операнды отличаются друг от друга, то текущая строка удаляется, а новая копируется в эту область памяти. Чтобы упростить присвоение, возвращается ссылка на строку, как в следующем примере:
String1 = String2 = String3;
Оператор индексирования перегружается дважды. В обоих случаях проверяются границы массива. Если пользователь попытается возвратить значение из ячейки памяти, находяшейся за пределами массива, будет возвращен последний символ массива (len-1).
В строках 117-128 оператор суммирования (+) выполняется как оператор конкатенации. Поэтому допускается создание новой строки из двух строк, как в следующем выражении:
String3 = String1 + String2;
Оператор (+) вычисляет длину новой строки и сохраняет ее во временной строке temp. Эта процедура вовлекает закрытый конструктор, который принимает целочисленный параметр и создает строку, заполненную значениями NULL. Нулевые значения затем замещаются символами двух строк. Первой копируется строка левого операнда (*this), после чего — строка правого операнда (rhs).
Первый цикл for последовательно добавляет в новую строку символы левой строки'. Второй цикл for выполняет ту же операцию с правой строкой. Обратите внимание, что счетчик i продолжает отсчет символов новой строки после того, как счетчик j начинает отсчет символов строки rhs.