|
|||||||
АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция |
Производные классы, наследованиеВажнейшим свойством объектно-ориентированного программирования является наследование. Для того, чтобы показать, что класс В наследует класс A (класс B выведен из класса A), в определении класса B после имени класса ставится двоеточие и затем перечисляются классы, из которых B наследует: class A { public: A(); ~A(); MethodA(); }; class B: public A { public: B(); ... }; Термин " наследование " означает, что класс B обладает всеми свойствами класса A, он их унаследовал. У объекта производного класса есть все атрибуты и методы базового класса. Разумеется, новый класс может добавить собственные атрибуты и методы. B b; b.MethodA(); // вызов метода базового класса Часто выведенный класс называют подклассом, а базовый класс – суперклассом. Из одного базового класса можно вывести сколько угодно подклассов. В свою очередь, производный класс может служить базовым для других классов. Изображая отношения наследования, их часто рисуют в виде иерархии или дерева.
Иерархия классов может быть сколь угодно глубокой. Если нужно различить, о каком именно классе идет речь, класс C называют непосредственным или прямым базовым классом класса D, а классA – косвенным базовым классом класса D. Предположим, что для библиотечной системы, которую мы разрабатываем, необходимо создать классы, описывающие различные книги, журналы и т.п., которые хранятся в библиотеке. Книга, журнал, газета и микрофильм обладают как общими, так и различными свойствами. У книги имеется автор или авторы, название и год издания. У журнала есть название, номер и содержание – список статей. В то же время книги, журналы и т.д. имеют и общие свойства: все это – "единицы хранения " в библиотеке, у них есть инвентарный номер, они могут быть в читальном зале, у читателей или в фонде хранения. Их можно выдать и, соответственно, сдать в библиотеку. Эти общие свойства удобно объединить в одном базовом классе. Введем класс Item, который описывает единицу хранения в библиотеке: class Item { public: Item(); ~Item(); // истина, если единица хранения на руках
bool IsTaken() const; // истина, если этот предмет имеется в библиотеке
bool IsAvailable() const; long GetInvNumber() const; // инвентарный номер
void Take(); // операция "взять" void Return(); // операция "вернуть"
private: // инвентарный номер — целое число long invNumber; // хранит состояние объекта - взят на руки bool taken; }; Когда мы разрабатываем часть системы, которая имеет дело с процессом выдачи и возврата книг, вполне достаточно того интерфейса, который представляет базовый класс. Например: // выдать на руки void TakeAnItem(Item& i) { ... if (i.IsAvailable()) i.Take(); } Конкретные свойства книги будут представлены классом Book. class Book: public Item { public: String Author(void) const; String Title(void) const; String Publisher(void) const; long YearOfPublishing(void) const; String Reference(void) const;
private: String author; String title; String publisher; short year; }; // автор // название // издательство // год выпуска // полная ссылка // на книгу Для журнала класс Magazine предоставляет другие сведения: class Magazine: public Item { public: String Volume(void) const; short Number(void) const; String Title(void) const; Date DateOfIssue() const; private: String volume; short number; String title; Date date; }; // том // номер // название // дата выпуска Ключевое слово public перед именем базового класса определяет, что внешний интерфейс базового класса становится внешним интерфейсом порожденного класса. Это наиболее употребляемый тип наследования. Описание защищенного и внутреннего наследования будет рассмотрено чуть позже. У объекта класса Book имеются методы, непосредственно определенные в классе Book, и методы, определенные в классе Item. Book b; long in = b.GetInvNumber(); String t = b.Reference(); Производный класс имеет доступ к методам и атрибутам базового класса, объявленным во внешней и защищенной части базового класса, однако доступ к внутренней части базового класса не разрешен. Предположим, в качестве части полной ссылки на книгу решено использовать инвентарный номер. Метод Reference класса Book будет выглядеть следующим образом: String Book::Reference(void) const { String result = author + "\n" + title + "\n" + String(GetInvNumber()); return result; } (Предполагается, что у класса String есть конструктор, который преобразует целое число в строку.) Запись: String result = author + "\n" + title + "\n" + String(invNumber); не разрешена, поскольку invNumber – внутренний атрибут класса Item. Однако если бы мы поместили invNumber в защищенную часть класса: class Item { ... protected: long invNumber; }; то методы классов Book и Magazine могли бы непосредственно использовать этот атрибут. Назначение защищенной (protected) части класса в том и состоит, чтобы, закрыв доступ "извне" к определенным атрибутам и методам, разрешить пользоваться ими производным классам. Если одно и то же имя атрибута или метода встречается как в базовом классе, так и в производном, то производный класс перекрывает базовый. class A { public: ... int foo(); ... }; class B: public A { public: int foo(); void bar(); }; void B::bar() { x = foo(); // вызывается метод foo класса B } Однако метод базового класса не исчезает. Просто при поиске имени foo сначала просматриваются атрибуты и методы самого класса. Если бы имя не было найдено, начался бы просмотр имен в базовом классе, затем просмотр внешних имен. В данном случае имя foo существует в самом классе, поэтому оно и используется. С помощью записи A::foo() можно явно указать, что нас интересует имя, определенное в классе A, и тогда запись: x = A::foo(); вызовет метод базового класса. Вообще, запись класс::имя уже многократно нами использовалась. При поиске имени она означает, что имя относится к заданному классу. Поиск по сайту: |
Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Студалл.Орг (0.01 сек.) |