КАТЕГОРИИ: Архитектура-(3434)Астрономия-(809)Биология-(7483)Биотехнологии-(1457)Военное дело-(14632)Высокие технологии-(1363)География-(913)Геология-(1438)Государство-(451)Демография-(1065)Дом-(47672)Журналистика и СМИ-(912)Изобретательство-(14524)Иностранные языки-(4268)Информатика-(17799)Искусство-(1338)История-(13644)Компьютеры-(11121)Косметика-(55)Кулинария-(373)Культура-(8427)Лингвистика-(374)Литература-(1642)Маркетинг-(23702)Математика-(16968)Машиностроение-(1700)Медицина-(12668)Менеджмент-(24684)Механика-(15423)Науковедение-(506)Образование-(11852)Охрана труда-(3308)Педагогика-(5571)Полиграфия-(1312)Политика-(7869)Право-(5454)Приборостроение-(1369)Программирование-(2801)Производство-(97182)Промышленность-(8706)Психология-(18388)Религия-(3217)Связь-(10668)Сельское хозяйство-(299)Социология-(6455)Спорт-(42831)Строительство-(4793)Торговля-(5050)Транспорт-(2929)Туризм-(1568)Физика-(3942)Философия-(17015)Финансы-(26596)Химия-(22929)Экология-(12095)Экономика-(9961)Электроника-(8441)Электротехника-(4623)Энергетика-(12629)Юриспруденция-(1492)Ядерная техника-(1748) |
Поля (атрибути) та методи
Екземпляри класів або об' єкти. Використання типів даних, визначених програмістом - одна з характерних рис структурного стилю програмування. Саме типізація відрізняє сучасні процедурні мови програмування (Модула, Паскаль, Сі, і т.д.) від своїх попередників. Тому визначення об' єкта як змінної деякого об' єктного типу є розвитком методології структурного стилю програмування. У об' єктно - орієнтованому програмуванні об' єктні типи звичайно називають класами, а змінні цих типів - екземплярами класів. Революційною ідеєю об' єктно - орієнтованої методології програмування є використання поняття спадкування як основного методу опису класів. Під спадкуванням розуміють таке відношення двох класів (об' єктних типів), при якому одному з них (дочірньому) приписуються атрибути, властивості і методи іншого (батьківського). У найбільш повному вигляді - у вигляді відкритого спадкування, якщо A і B - класи (об' єктні типи) і B успадковує A, це означає, що всі атрибути A, за означенням, є атрибутами B, і всі методи A, за означенням, є методами B. При закритому спадкуванні клас В одержує від класу А в спадщину тільки виділену частину атрибутів і методів. Клас A можна назвати класом-предком, B - нащадком. Наприклад, клас ((об' єктний тип) Людина може породити об' єктні типи Студент і Викладач. У цьому випадку говорять, що клас Студент (відповідно, Викладач) успадковує клас Людина.
Щоб похідні класи були не просто зручною формою короткого опису, в реалізації мови має бути вирішене питання: до якого з похідних класів відноситься об'єкт, на який дивиться покажчик base*? Існує три основні способи відповіді,: [1] Забезпечити, щоб покажчик міг посилатися на об'єкти тільки одного типу ($$6.4.2); [2] Помістити в базовий клас поле типу, яке зможуть перевіряти функції; [3] використовувати віртуальні функції ($$6.2.5). Покажчики на базові класи звичайно використовуються при проектуванні контейнерних класів (множина, вектор, список і так далі). Тоді у разі [1] ми отримаємо однорідні списки, тобто списки об'єктів одного типу. Способи [2] і [3] дозволяють створювати різнорідні списки, тобто списки об'єктів декількох різних типів (насправді, списки покажчиків на ці об'єкти). Спосіб [3] - це спеціальний надійний в сенсі типу варіант способу [2]. Особливо цікаві і потужні варіанти дають комбінації способів [1] і [3]. Спочатку обговоримо простий спосіб з полем типу, тобто спосіб [2]. Приклад з класами manager/employee можна перевизначити так: struct employee { enum empl_type { M, E }; empl_type type; employee* next; char* name; short department; //... }; struct manager: employee { employee* group; short level; //... }; Маючи ці визначення, можна написати функцію, що друкує дані про довільного службовця,: void print_employee(const employee* e) { switch (e ->type){ case E: cout << e ->name << '\t' << e ->department << '\n'; //... break; case M: cout << e ->name << '\t' << e ->department << '\n'; //... manager* p = (manager*) e; cout << "level" << p ->level << '\n'; //... break; } } Надрукувати список службовців можна так: void f(const employee* elist) { for (; elist; elist=elist ->next) print_employee(elist); } Це цілком хороше рішення, особливо для невеликих програм, написаних однією людиною, але воно має істотний недолік: транслятор не може перевірити, наскільки правильно програміст поводиться з типами. У великих програмах це призводить до помилок двох видів. Перший - коли програміст забуває перевірити поле типу. Другий - коли в перемикачі вказуються не усі можливі значення поля типу. Цих помилок досить легко уникнути в процесі написання програми, але зовсім нелегко уникнути їх при внесенні змін в нетривіальну програму, а особливо, якщо це велика програма, написана кимось іншим. Ще важче уникнути таких помилок тому, що функції типу print() часто пишуться так, щоб можна було скористатися спільністю класів: void print(const employee* e) { cout << e ->name << '\t' << e ->department << '\n'; //... if (e ->type == M){ manager* p = (manager*) e; cout << "level" << p ->level << '\n'; //... } } Оператори if, подібні до приведених в прикладі, складно знайти у великій функції, що працює з багатьма похідними класами. Але навіть коли вони знайдені, нелегко зрозуміти, що відбувається насправді. Крім того, при всякому додаванні нового виду службовців потрібно зміни в усіх важливих функціях програми, тобто функціях, перевіряючих поле типу. В результаті доводиться правити важливі частини програми, збільшуючи тим самим час на відладку цих частин.
Дата добавления: 2013-12-14; Просмотров: 731; Нарушение авторских прав?; Мы поможем в написании вашей работы! Нам важно ваше мнение! Был ли полезен опубликованный материал? Да | Нет |