Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву
Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Конструкторы производного классаСодержание книги Поиск на нашем сайте Если в данной программе нам понадобится инициализировать значением объект класса CountPr (например с2=--с1; с2=++с1;), то компилятор не позволит использовать конструктор базового класса с одним аргументом, потому что в нём возвращаемым типом данных является тип Count. В связи с этим, мы должны написать новый конструктор для производного класса. class Count { //áàçîâûé êëàññ … }; //--------------------------------------------------------------------------- class CountPr: public Count { // ïðîèçâîäíûé êëàññ public: CountPr() { c = 0; } CountPr(int d) { c = d; } CountPr operator--() { --c; return CountPr(c); } }; //--------------------------------------------------------------------------- int main() { CountPr c1, c2; // îáúåêò ñ1 ïðîèçâîäíîãî êëàññà cout << "\n c1=" << c1.get(); //увидим c1=0 ++c1; ++c1; ++c1; cout << "\n c1=" << c1.get(); //увидим c1=3 c2=c1; c2=--c1; cout << "\n c2=" << c2.get(); //увидим c2=2 getch(); return 0; } Существует также альтернативный вариант записи конструктора производного класса: class CountPr: public Count { // ïðîèçâîäíûé êëàññ public: CountPr(): Count() { } CountPr(int d): Count(d) { } CountPr operator--() { --c; return CountPr(c); } }; Здесь использован новый вид записи конструктора производного класса. Конструктор CountPr(): Count() вызывает конструктор базового класса Counter, который и выполняет нужные действия. Когда инициализируется значением объект с2 (с2=--с1;), то при этом вызывается конструктор с одним аргументом класса CountPr, который вызывает соответствующий конструктор с одним аргументом из базового класса. Конструкция CountPr(int d): Count (d) означает, что аргумент "d" будет передан от конструктора CountPr() в Count(), где будет использован для инициализации объекта.
Перегрузка функций Существует возможность определять для производного класса методы, имеющие такие же имена, как и у методов базового класса. В этом случае имеет место перегрузка функций. Такая возможность может понадобиться, если для объектов базового и производного классов в вашей программе используются одинаковые вызовы. На одном из предыдущих занятий мы рассматривали программу, которая позволяла помещать числа в стек, а затем извлекать их. Допустим, что базовый класс не содержал в себе проверку на переполнение и при попытке отправить в стек слишком много чисел программа могла зависнуть по причине переполнения массива. При извлечении количества чисел, большего, чем находится в стеке, результат мог быть бессмысленным. Для исправления этих ошибок с помощью технологии наследования создадим производный класс Stack2. class Stack { protected: enum { MAX = 3 }; // размер стека int st[MAX]; // данные, хранящиеся в стеке int top; // индекс последнего элемента в стеке public: Stack() // конструктор { top = -1; } void push(int var) // помещение числа в стек { st[++top] = var; } int pop() // извлечение числа из стека { return st[top--]; } }; //--------------------------------------------------------------------------- class Stack2: public Stack { public: void push(int var) { // помещение числа в стек if (top > MAX-1) cout << "\nError: stack polon!"; // если стек полон, то ошибка Stack::push (var); // если всё в порядке, то вызов функции push класса Stack } int pop() { // извлечение числа из стека if (top < 0) cout << "\nError: stack pust!\n"; // если стек пуст, то ошибка return Stack::pop(); // если всё в порядке, то вызов функции pop класса Stack } }; //--------------------------------------------------------------------------- int main() { Stack2 s1; s1.push(11); // поместим в стек несколько чисел s1.push(22); s1.push(33); cout << endl << s1.pop(); // заберем числа из стека cout << endl << s1.pop(); cout << endl << s1.pop(); cout << endl << s1.pop(); //!!!, а данных-то больше нет return 0; } Как видно из данного примера, в классе Stack2 содержатся два метода push() и pop(), которые имеют те же имена, аргументы и возвращаемые значения, что и методы базового класса. В связи с этим возникает вопрос: Как компилятор поймёт, какой из методов вызвать? Существует правило: если один и тот же метод существует и в базовом, и в производном классе, то будет выполнен метод производного класса. Это правило справедливо только для объектов производного класса и не справедливо для объектов базового класса, поскольку им ничего не известно о производном классе, поэтому они всегда пользуются методами базового класса. В нашем примере, в связи с тем что s1 – это объект производного класса Stack2, будет выполнен метод push() класса Stack2. Если стек полон, то метод пошлёт сообщение об ошибке, если – нет, то посредством строки Stack::push (var); вызывается метод push() базового класса Stack. Иерархия классов До сих пор мы использовали наследование только для добавления новых возможностей к существующим классам. Теперь рассмотрим пример, где наследование применяется как часть первоначальной разработки программы. В качестве примера рассмотрим базу данных служащих некоторой компании, в которой существует только две категории служащих: менеджеры, занятые управлением, и рабочие, занятые изготовлением товара. В базе данных хранятся имена служащих всех категорий и их идентификационные номера. В информации о менеджерах содержится ещё название их должности и заработная плата, а в информации о рабочих – квалификационный разряд.
Программа будет состоять из базового класса, который содержит фамилии служащих и их номера и порождает два новых класса. const int L = 80; //--------------------------------------------------------------------------- class Sotrudnik { //áàçîâûé êëàññ private: char name[L]; int number; public: void getdata() { cout << "\n Vvedite FIO: "; cin.getline(name, L); cout << " Vvedite nomer: "; cin >> number; } void show() const { cout << "\n Familiya: " << name; cout << "\n Nomer: " << number; } }; //--------------------------------------------------------------------------- class Manager: public Sotrudnik { //ïðîèçâîäíûé êëàññ private: char dolgnost[L]; double oklad; public: void getdata() { Sotrudnik::getdata(); cout << " Vvedite dolgnost: "; cin >> dolgnost; cout << " Vvedite zarplatu: "; cin >> oklad; } void show() const { Sotrudnik::show(); cout << "\n Dolgnost: " << dolgnost; cout << "\n Zar. plata: " << oklad; } }; //--------------------------------------------------------------------------- class Worker: public Sotrudnik { private: int raz; public: void getdata() { Sotrudnik::getdata(); cout << " Vvedite razryad: "; cin >> raz; } void show() const { Sotrudnik::show(); cout << "\n Razryad: " << raz; } }; //--------------------------------------------------------------------------- int main() { Manager m1; Worker r1, r2; cout << "\nVvod managerov: "; m1.getdata(); cin.get(); cout << "\nVvod workerov: "; r1.getdata(); cin.get(); r2.getdata(); cout << "\nVyvod managerov: "; m1.show(); cout << "\nVyvod workerov: "; r1.show(); r2.show(); getch(); return 0; } Обратите внимание на то, что данные базового класса объявлены с ключевым словом private. Это вызвано тем, что производным классам нет необходимости использовать эти данные напрямую. Они используют вызов методов базового класса, которые в свою очередь имеют полный доступ к данным. В данной программе мы не определяли объекты класса Sotrudnik, а использовали его как общий базовый класс для производных классов. Здесь, ни в в базовом, ни в производных классах нет конструкторов, поэтому компилятор использует конструктор по умолчанию производного класса, вызывающий конструктор по умолчанию базового класса.
Варианты написания программы Вариант 2 При определении производных классов Manager и Worker можно было-бы использовать спецификатор private (частное наследование), например: class Manager: private Sotrudnik {…} class Worker: private Sotrudnik {…} Это можно было сделать, поскольку объекты производных классов, не используют методы базового класса. В методах производных классов используется только вызов методов базового класса. Следует понимать, когда можно использовать частное наследование, а когда – нельзя. Так, если объекту производного класса необходимо использовать непроизводный метод базового класса напрямую, то в этом случае необходимо применять общее наследование (public). Например: … class Manager: public Sotrudnik { private: char dolgnost[L]; double oklad; public: void getdata() { Sotrudnik::getdata(); cout << " Vvedite dolgnost: "; cin >> dolgnost; cout << " Vvedite zarplatu: "; cin >> oklad; } // void show() const {…} отсутствует этот метод }; … int main() { Manager m1; … cout << "\nVyvod managerov: "; m1.show(); // вызовется метод базового класса … } При необходимости скрыть все методы базового класса от объектов производного класса необходимо применять частное наследование. Вариант 3 Здесь, в главной функции для ввода данных о первом рабочем мы использовали оператор r1.getdata();. Если в методе getdata() производного класса убрать вызов одноимённого метода базового класса, то тогда в главной функции вместо оператора r1.getdata(); надо было-бы написать следующее: r1.Sotrudnik::getdata(); r1.getdata();. Только в этом случае обязательно необходимо использовать общее наследование, т.е. class Worker: public Sotrudnik { … };.
|
||||||||||||||||||
|
Последнее изменение этой страницы: 2016-04-08; просмотров: 508; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 216.73.217.128 (0.009 с.) |