Главная страница Случайная страница КАТЕГОРИИ: АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника |
Функции друзья и перегрузка оператора
В листинге 15.1 представлен класс String, в котором перегружается operator+. В нем также объявляется конструктор, принимающий указатель на константную строку, поэтому объект класса String можно создавать из строки с концевым нулевым символом.
Примечание: Строки в С и C++ представляют собой массивы символов, заканчивающиеся концевым нулевым символом. Такая строка получается, например, в следующем выражении присвоения: myString[] = " Hello World".
Но чего невозможно сделать в классе String, так это получить новую строку в результате сложения объекта этого класса с массивом символов: char cString[] = { " Hello" }; String sString(" Worid"); String sStringTwo = cString + sString; //ошибка! Строки нельзя использовать с перегруженной функции operator+. Как объяснялось на занятии 10, выражение cString + sString на самом деле вызывает функцию cString.operator+(sString). Поскольку функция operator+() не может вызываться для символьной строки, данная попытка приведет к ошибке компиляции. Эту проблему можно решить, объявив функцию-друга в классе String, которая перегружает operator+ таким образом, чтобы суммировать два объекта String. Соответствующий конструктор класса String преобразует строки в объекты String, после чего вызывается функция-друг operator+, выполняющая конкатенацию двух объектов. Листинг 15.8. Функция-друг operator+ 1: // Листинг 15.8. Операторы друзья 2: 3: #include < iostream.h> 4: #include < string.h> 5: 6: // Рудиментарный класс string 7: class String 8: { 9: public: 10: // constructors 11: String(); 12: String(const char *const); 13: String(const String &); 14: ~String(); 15: 16: // перегруженные операторы 17: char & operator[](int offset); 18: char operator[](int offset) const; 19: String operator+(const String&); 20: friend String operator+(const String&, const String&); 21: void operator+=(const String&); 22: String & operator= (const String &); 23: 24: // методы общего доступа 25: int GetLen()const { return itsLen; } 26: const char * GetString() const { return itsString; } 27: 28: private: 29: String (int); // закрытый конструктор 30: char * itsString; 31: unsigned short itsLen; 32: }; 33: 34: // конструктор, заданный по умолчанию, создает строку длиной 0 байт 35: String:: String() 36: { 37: itsString = new char[1]; 38: itsString[0] = '\0'; 39: itsLen=0; 40: // cout < < " \tDefault string constructor\n"; 41: // ConstructorCount++: 42: } 43: 44: // закрытый конструктор, используемый только 45: // методами класса для создания новой строки 46: // указанного размера, заполненной нулями. 47: String:: String(int len) 48: { 49: itsString = new char[len+1]; 50: for (int i = 0; i< =len; i++) 51: itsString[i] = '\0'; 52: itsLen=len; 53: // cout < < " \tString(int) constructor\n"; 54: // ConstructorCount++; 55: } 56: 57: // Преобразует массив символов в строку 58: String:: String(const char * const cString) 59: { 60: itsLen = strlen(cString); 61: itsString = new char[itsLen+1]; 62: for (int i = 0; i< itsLen; i++) 63: itsString[i] = cString[i]; 64: itsString[itsLen]='\0'; 65: // cout < < " \tString(char*) constructor\n"; 66: // ConstructorCount++; 67: } 68: 69: // конструктор-копировщик 70: String:: String (const String & rhs) 71: { 72: itsLen=rhs.GetLen(); 73: itsString = new char[itsLen+1]; 74: for (int i = 0; i< itsLen; i++) 75: itsString[i] = rhs[i]; 76: itsString[itsLen] = '\0'; 77: // cout < < " \tString(String&) constructor\n"; 78: // ConstructorCount++; 79: } 80: 81: // деструктор, освобождает занятую память 82: String:: ~String () 83: { 84: delete [] itsString; 85: itsLen = 0; 86: // cout < < " \tString destructor\n"; 87: } 88: 89: // этот оператор освобождает память, а затем 90: // копирует строку и размер 91: String& String:: operator=(const String & rhs) 92: { 93: if (this == & rhs) 94: return < < this; 95: delete [] itsString; 96: itsLen=rhs.GetLen(); 97: itsString = new char[itsLen+1]; 98: for (int i = 0; i< itsLen; i++) 99: itsString[i] = rhs[i]; 100: itsString[itsLen] = 1\0'; 101: return *this; 102: // cout < < " \tString operator=\n"; 103: } 104: 105: // неконстантный оператор индексирования, 106: // возвращает ссылку на символ, который можно 107: // изменить! 108: char & String:: operator[](int offset) 109: { 110: if (offset > itsLen) 111: return itsString[itsLen-1]; 112: else 113: return itsString[offset]; 114: } 115: 116: // константный оператор индексирования, 117: // используется для константных объектов (см. конструктор-копировщик!) 118: char String:: operator[](int offset) const 119: { 120: if (offset > itsLen) 121: return itsString[itsLen-1]; 122: else 123: return itsString[offset]; 124: } 125: // создает новый объект String, добавляя 126: // текущий обьект к rhs 127: String String:: operator+(const String& rhs) 128: { 129: int totalLen = itsLen + rhs.GetLen(); 130: String temp(totalLen); 131: int i, j; 132: for (i = 0; i< itsLen; i++) 133: temp[i] = itsString[i]; 134: for (j = 0, i = itsLen; j< rhs.GetLen(); j++, i++) 135: temp[i] = rhs[j]; 136: temp[totalLen]='\0'; 137: return temp; 138: } 139: 140: // создает новый объект String 141: // из двух объектов класса String 142: String operator+(const String& lhs, const String& rhs) 143: { 144: int totalLen = lhs.GetLen() + rhs.GetLen(); 145: String temp(totalLen); 146: int i, j; 147: for (i = 0; i< lhs.GetLen(); i++) 148: temp[i] = lhs[i]; 149: for (j = 0, i = lhs.GetLen();; j< rhs.GetLen(); j++, i++) 150: temp[i] = rhs[j]; 151: temp[totalLen]='\0'; 152: return temp; 153: } 154: 155: int main() 156: { 157: String s1(" String 0ne "); 158: String s2(" String Two "); 159: char *c1 = { " C-String 0ne " }; 160: String s3; 161: Stnng s4; 162: String s5; 163: 164: cout < < " s1: " < < s1.GetString() < < endl; 165: cout < < " s2: " < < s2.GetString() < < endl; 166: cout < < " c1: " < < c1 < < endl; 167: s3 = s1 + s2; 168: cout < < " s3: " < < s3.GetString() < < endl; 169: s4 = s1 + cl; 170: cout < < " s4: " < < s4.GetStnng() < < endl; 171: s5 = c1 + s2; 172: cout < < " s5: " < < s5.GetString() < < endl; 173: return 0; 174: }
Результат: s1: String 0ne s2: String Two c1: C-String One s3: String One String Two s4: String One C-String One s5: C-String One String Two
Анализ: Объявления всех методов класса String, за исключением operator+, остались такими же, как в листинге 15.1. В строке 20 листинга 15.8 перегружается новый operator+, который принимает две ссылки на константные строки и возвращает строку, полученную в результате конкатенации исходных строк. Эта функция объявлена как друг класса String. Обратите внимание, что функция operator+ не является функцией-членом этого или любого другого класса. Она объявляется среди функций-членов класса string как друг, но не как член класса. Тем не менее это все же полноценное объявление функции, и нет необходимости еще раз объявлять в программе прототип этой функции. Выполнение функции operator+ определяется в строках 142—153. Определение выполнения функции аналогично приведенному в версии программы, представленной в листинге 15.1, за тем исключением что функция принимает в качестве аргументов две строки, обращаясь к ними с помощью открытых методов доступа класса. Перегруженный оператор применяется в строке 171, где выполняется конкатенация двух строк.
|