Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
День 15-й. Дополнительные возможности наследования
До настоящего момента вы использовали одиночное и множественное наследование для создания относительно простых связей между классами. Сегодня вы узнаете: • Что такое вложение и как его использовать • Что такое делегирование и как его использовать • Как выполнить один класс внутри другого • Как использовать закрытое наследование Вложение
Анализируя примеры, приведенные на предыдущих занятиях, вы, вероятно, заметили, что в классах допускается использование в переменных-членах объектов других классов. В этом случае программисты на C++ говорят, что внешний класс содержит внутренний. Так, класс Employee в качестве переменных-членов может содержать строковые объекты (с именем сотрудника) и объекты с целочисленными значениями (зарплатой и т.д.). В листинге 15.1 представлен незавершенный, но весьма полезный класс String. Запуск такой программы не приведет к выводу каких-либо результатов, но она потребуется при написании других программ этого занятия. Листинг 15.1. Класс string 1: #include < iostream.h> 2: #include < string.h> 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: 20: // Общие методы доступа 21: int GetLen()const { return itsLen; } 22: const char * GetString() const { return itsString; } 23: // статический целочисленный счетчик ConstructorCount; 24: 25: private: 26: String (int); // закрытый конструктор 27: char * itsString; 28: unsigned short itsLen; 29: 30: }; 31: 32: // конструктор класса String пo умолчанию создает строку длиной 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: // методами клаcса для создания новой cтроки 44: // указанного размера, заполненной нулями 45: String:: String(int len) 46: { 47: itsString = new ohar[len+1]; 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: // Преобразует массив символов в cтроку 56: String:: String(const char * oonst cString) 57: { 58: itsLen = strlen(cString); 59: itsString = new char[itsLen+1]; 60: for (int i = 0; i< itsLen; 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< itsLen; 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< itsLen; 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 itsStnng[offset]; 112: } 113: 114: // константный оператор индексирования, 115: // используется для константных объектов (см. конструктор-копировщик! ) 116: char String:: operator[](int offset) const 117: { 118: if (offset > itsLen) 119: return itsString[itsLen-1]; 120: else 121: return itsString[offset]; 122: } 123: 124: // создает новую строку, добавляя текущую 125: // строку к rhs 126: String String:: operator+(const String& rhs) 127: { 128: int totalLen = itsLen + rhs.GetLen(); 129: String temp(totalLen); 130: int i, j; 131: for (i = 0; i< itsLen; i++) 132: temp[i] = itsString[i]; 133: for (j = 0: j< rhs.GetLen(); j++, i++) 134: temp[i] = rhs[j]; 135: temp[totalLen]='\0'; 136: return temp; 137: } 138: 139: // изменяет текущую строку, ничего не возвращая 140: void String:: operator+=(const String& rhs) 141: { 142: unsigned short rhsLen = rhs.GetLen(); 143: unsigned short totalLen = itsLen + rhsLen; 144: String temp(totalLen); 145: int i, j; 146: for (i = 0; i< itsLen; i++) 147: temp[i] = itsString[i]; 148: for (j = 0; j< rhs.GetLen(); j++, i++) 149: temp[i] = rhs[i-itsLen]; 150: temp[totalLen]='\0'; 151: *this = temp; 152: } 153: 154: // int String:: ConstructorCount = 0;
Результат: Нет
Анализ: Представленный в листинге 15.1 класс String напоминает другой класс, использованный в листинге 12.12. Однако есть одно важное отличие между этими двумя классами: конструкторы и некоторые функции листинга 12.12 включали операторы вывода на печать, благодаря которым на экране отображались сообщения об их использовании. В листинге 15.1 эти операторы временно заблокированы, но они будут использоваться в следующих примерах. Статическая переменная-член ConstructorCount объявляется и инициализируется соответственно в строках 23 и 154. Значение этой переменной увеличивается на единицу при вызове любого конструктора класса String. Эти функции также заблокированы и будут использоваться в следующих листингах. В листинге 15.2 объявляется класс Employee, содержащий три объекта класса String. Листинг 15.2. Класс Employee 1: #include " String.hpp" 2: 3: class Employee 4: { 5: 6: public: 7: Employee(); 8: Employee(char *, char *, char > >, long); 9: ~Employee(); 10: Employee(const Employee& ); 11: Employee & operator= (const Employee & ); 12: 13: const String & GetFirstName() const 14: { return itsFirstName; } 15: const String & GetLastName() const { return itsLastName; } 16: const String & GetAddress() const { return itsAddress; } 17: long GetSalary() const { return itsSalary; } 18; 19: void SetFirstName(const String & fNama) 20: { itsFirstName = fName; } 21: void SetLastName(const String & lNama) 22: { itsLastName = lNamo; } 23: void SetAddress(const String & address) 24: { itsAddress = address; } 25: void SetSalary(long salary) { itsSalary = salary; } 26: private: 27: String itsFirstName; 28: String itsLastName; 29: String itsAddress; 30: long itsSalary; 31: }; 32: 33: Employee:: Employee(); 34: itsFirstName(" " ), 35: itsLastName(" " ), 36: itsAddress(" " ), 37: itsSalary(0) 38: { } 39: 40: Employee:: Employee(char * firstName, char * lastName, 41: char * address, long salary): 42: itsFirstName(firstName), 43: itsLastName(lastName), 44: itsAddress(address), 45: itsSalary(salary) 46: { } 47: 48: Employee:: Employee(const Employee & rhs): 49: itsFirstName(rhs.GetFirstName()), 50: itsLastName(rhs, GetLastName()), 51: itsAddress(rhs, GetAddress()), 52: itsSalary(rhs.GetSalary()) 53: { } 54: 55: Employee:: ~Employea() { } 56: 57: Employee & Employae:: Qperator= (const Employee & rhs) 58: { 59: if (thls — & rhs) 60: return *this; 61: 62: itsFlrstName = rhs.GetFlrstName(); 63: itsLastName = rhs, GetLastName(); 64: itsAddress = rhs, GetAddress(); 65: itsSalary = rhs, GetSalary(); 66: 67: return *thls; 68: } 69: 70: int main() 71: { 72: Employee Edie(" Jane", " Doe", " 1461 Shore Parkway", 20000); 73: Edie.SetSalary(50000); 74: String LastName(" Levine" ); 75: Edie.SetLastName(LastName); 76: Edie.SetFirstName(" Edythe" ); 77: 78: cout < < " Имя: "; 79: cout < < Edie.GetFirstName().GetString(); 80: cout < < " " < < Edie.GetLastName().GetString(); 81: cout < < ".\nАдрес: "; 82: cout < < Edie.GetAddress().GetString(); 83: cout < < ".\nЗарплата: " ; 84: cout < < Edie.GetSalary(); 85: return 0; 86: }
Примечание: Сохраните листинг 15.1 в файле с именем string. hpp. Затем всякий раз, когда понадобится класс String, вы сможете вставить листинг 15.1, просто добавив строку #include " String.hpp". Это первая строка в листинге 15.2.
Результат: Name: Edythe Levine. Address: 1461 Shore Parkway. Salary: 50000
Анализ: В листинге 15.2 объявляется класс Employee, переменными-членами которого выступают три объекта класса String — itsFirstName, itsLastName и itsAddress. В строке 72 создается объект Employee, который инициализируется четырьмя значениями. В строке 73 вызывается метод доступа SetSalary класса Employee, который принимает константное значение 50000. В реальной программе это значение определялось бы либо динамически в процессе выполнения программы, либо устанавливалось бы константой. В строке 74 создается и инициализируется строковой константой объект класса String, который в строке 75 используется в качестве аргумента функции SetLastName(). В строке 76 вызывается метод SetFirstName класса Employee с еще одной строковой константой в качестве параметра. Однако если вы обратитесь к объявлению класса Employee, то увидите, что в нем нет функции SetFirstName(), принимающей строку символов как аргумент. Для функции SetFirstName() в качестве параметра задана константная ссылка на объект String. Тем не менее компилятор не покажет сообщения об ошибке, поскольку в строке 9 листинга 15.1 объявлен конструктор, создающий объект String из строковой константы. Популярное:
|
Последнее изменение этой страницы: 2017-03-08; Просмотров: 570; Нарушение авторского права страницы