Студопедия

Главная страница Случайная страница

Разделы сайта

АвтомобилиАстрономияБиологияГеографияДом и садДругие языкиДругоеИнформатикаИсторияКультураЛитератураЛогикаМатематикаМедицинаМеталлургияМеханикаОбразованиеОхрана трудаПедагогикаПолитикаПравоПсихологияРелигияРиторикаСоциологияСпортСтроительствоТехнологияТуризмФизикаФилософияФинансыХимияЧерчениеЭкологияЭкономикаЭлектроника






Функции друзья и перегрузка оператора






 

В листинге 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, где выполняется конкатенация двух строк.

 






© 2023 :: MyLektsii.ru :: Мои Лекции
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав.
Копирование текстов разрешено только с указанием индексируемой ссылки на источник.