Анализ:Объявления всех методов класса String, за исключением operator+, остались такими же, как в листинге 15.1. В строке 20 листинга 15.8 перегружается новый operator+, который принимает две ссылки на константные строки и возвращает строку, полученную в результате конкатенации исходных строк. Эта функция объявлена как друг класса String.
Обратите внимание, что функция operator+ не является функцией-членом этого или любого другого класса. Она объявляется среди функций-членов класса string как друг, но не как член класса. Тем не менее это все же полноценное объявление функции, и нет необходимости еще раз объявлять в программе прототип этой функции.
Выполнение функции operator+ определяется в строках 142—153. Определение выполнения функции аналогично приведенному в версии программы, представленной в листинге 15.1, за тем исключением что функция принимает в качестве аргументов две строки, обращаясь к ними с помощью открытых методов доступа класса.
Перегруженный оператор применяется в строке 171, где выполняется конкатенация двух строк.
Функции-друзья
Для объявления функции как друга класса используется ключевое слово friend, за которым следует объявление функции Это не предоставляет функции доступ к указателю this, но обеспечивает доступ ко всем закрытым и защищенным данным и функциям-членам.
Пример:
class PartNode
{ // ...
// сделаем функцию-член другого класса другом этого класса
friend void PartsList::Insert(Part*)
// сделаем другом глобальную функцию
friend int SomeFunction();
// ...
};
Перегрузка оператора вывода
Настало время снабдить наш класс String возможностью использовать объект cout для вывода своих данных так же, как при выводе данных базовых типов. До сих пор для вывода значения переменной-члена приходилось использовать следующее выражение:
cout << theString.GetString();
Неплохо было бы иметь возможность написать просто
cout << theString;
Для этого необходимо перегрузить функцию operator<<(). Более подробно использование потоков iostreams для вывода данных обсуждается на занятии 16. А в листинге 15.9 объявляется перегрузка функции operator<< как друга.
Листинг 15.8. Перегрузка operator<<()
1: #include
2: #include
3:
4: class String
5: {
6: public:
7: // конструкторы
8: String();
9: String(const char *const);
10: String(const String &);
11: ~String();
12:
13: // перегруженные операторы
14: char & operator[](int offset);
15: char operator[](int offset) const;
16: String operator+(const String&);
17: void operator+=(const String&);
18: String & operator= (const String &);
19: friend ostream& operator<<
20: (ostream& theStream,String& theString);
21: // Общие методы доступа
22: int GetLen()const { return itsLen; }
23: const char * GetString() const { return itsString; }
24:
25: private:
26: String (int); // закрытый конструктор
27: char * itsString;
28: unsigned short itsLen;
29: };
30:
31:
32: // конструктор, заданный no умолчанию, создает строку длиной 0 байт
33: String::String()
34: {
35: itsString = new char[1];
36: itsString[0] = '\0' ;
37: itsLen=0;
38: // cout << "\tDefault string constructor\n";
39: // ConstructorCount++;
40: }
41:
42: // закрытый конструктор, используемый только
43: // методами класса для создания новой строки
44: // указанного размера, заполненной значениями NULL.
45: String::String(int len)
46: {
47: itsString = new char[k:.H];
48: for (int i = 0; i<=len; i++)
49: itsString[i] = '\0';
50: itsLen=len;
51: // cout << "\tString(int) constructor\n";
52: // ConstructorCount++;
53: }
54:
55: // Преобразует массив символов в строку
56: String::String(const char * const cString)
57: {
58: itsLen = strlen(cString);
59: itsString = new char[itsLen+1];
60: for (int i = 0; i
61: itsString[i] = cString[i];
62: itsString[itsLen]='\0';
63: // cout << "\tString(char*) constructor\n";
64: // ConstructorCount++;
65: }
66:
67: // конструктор-копировщик
68: String::String (const String & rhs)
69: {
70: itsLen=rhs.GetLen();
71: itsString = new char[itsLen+1];
72: for (int i = 0; i
73: itsString[i] = rhs[i];
74: itsString[itsLen] = '\0';
75: // cout << "\tString(String&) constructor\n";
76: // ConstructorCount++;
77: }
78:
79: // деструктор освобождает занятую память
80: String::~String ()
81: {
82: delete [] itsString;
83: itsLen = 0;
84: // cout << "\tString destructor\n";
85: }
86:
87: // оператор равенства освобождает память, а затем
88: // копирует строку и размер
89: String& String::operator=(const String & rhs)
90: {
91: if (this == &rhs)
92: return *this;
93: delete [] itsString;
94: itsLen=rhs.GetLen();
95: itsString = new char[itsLen+1];
96: for (int i = 0; i
97: itsString[i] = rhs[i];
98: itsString[itsLen] = '\0';
99: return *this;
100: // cout << "\tString operator=\n";
101: }
102:
103: // неконстантный оператор индексирования,
104: // возвращает ссылку на символ, который можно
105: // изменить!
106: char & String::operator[](int offset)
107: {
108: if (offset > itsLen)
109: return itsString[itsLen-1];
110: else
111: return itsString[offset];
112: }
113:
114: // константный оператор индексирования,
Читать дальше