Виклик методів похідного класу 


Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

Виклик методів похідного класу



Клас Stack2 містить два методи: push() і pop(). Ці методи мають ті ж імена, аргументи і повернуті значення, що й методи класу Stack. Якщо ми викликаємо ці методи з функції main() оператором типу

s1.push(11);

то як компілятор зрозуміє, який з двох методів push() викликати? Існує правило: якщо один і той самий метод існує і в базовому, і в похідному класі, то буде викликаний метод похідного класу. (Це правило діє для об’єктів похідного класу, оскільки базовому класу взагалі нічого не відомо про похідний клас, то його об’єкти викликатимуть методи базового класу). В цьому випадку ми говоримо, що метод похідного класу перезавантажує метод базового класу. Для нашого прикладу, оскільки s1 - об’єкт класу Stack2, то буде викликаний метод push() класу Stack2.

Метод push() класу Stack2 перевіряє, чи повний стек: якщо так, то він посилає повідомлення про помилку і закриває програму, якщо ні, то викликається метод push() класу Stack. Так само метод pop() класу Stack2 здійснює перевірку того, чи стек не порожній. Якщо так, то виводиться повідомлення про помилку, інакше викликається метод pop() базового класу Stack.

 

Операція дозволу і перезавантаження функцій

Як методи push() і pop() класу Stack2 дістають доступ до методів push() і pop() класу Stack? Вони використовують операцію дозволу:: у такий спосіб

Stack::push(var);

Stack::pop();

В цих рядках визначено, що будуть викликані методи класу Stack. Без операції дозволу компілятор вирішить, що методи push() і pop() викликають самі себе, що в нашому випадку призведе до помилки програми. Використання методу дозволу дає змогу точно визначити, до якого класу відноситься викликаний метод.

 

Складніший приклад успадковування

Розглянемо складніший приклад використання успадковування. Раніше ми ввели клас Distance (починаючи з програми 11.3), в якому припускалося, що інтервал може мати тільки додатнє значення. Створимо новий похідний клас, який міститиме додаткове поле, куди будемо записувати знак – додатній або від’ємний. Також змінимо методи класу, щоб вони могли працювати зі знаковим значенням інтервалу. Далі приведено лістінг програми 11.5

#include <iostream.h>

#include <conio.h>

#include <bios.h>

enum posneg{pos,neg};

class Distance

{protected:

int feet;

float inches;

public:

 

Distance():feet(0),inches(0.0) //конструктор без аргументів

{ }

//конструктор з 2 аргументами

Distance(int ft,float in):feet(ft),inches(in)

{ }

 

void getdist()

{cout <<"\nВведіть число футів "; cin >>feet;

cout << "Дюймів "; cin>>inches;

}

 

void showdist()

{cout <<feet << "\' "<< inches <<"\''";}

};

//////////////

class DistSign:public Distance

{

private:

posneg sign;

public:

DistSign():Distance()

{sign=pos;}

 

DistSign(int ft,float in,posneg sg=pos):Distance(ft,in)

{

sign=sg;

}

 

void getdist()

{ Distance::getdist();

char ch;

cout<<"Введіть + чи -";

ch=getch();

if (ch=='+')

sign=pos;

else

sign=neg;

}

 

void showdist() const

{cout<<((sign==pos)?"(+)":"(-)");

Distance::showdist();

}

};

///////////////

int main()

{

clrscr();

DistSign alpha;

alpha.getdist();

DistSign beta(11,6.25);

DistSign gamma(100,5.5,neg);

//Вивід

cout<<"\nA=";alpha.showdist();

cout<<"\nB=";beta.showdist();

cout<<"\nC=";gamma.showdist();

cout<<endl;

bioskey(0);

return 0;

}

 

Програма 11.5

Ми ввели клас DistSign, до якого додали можливість роботи зі знаковими числами. Клас Distance в цій програмі такий сам, як і в попередньому, з тією різницею, що його дані описані як protected. Фактично в цьому випадку специфікатор міг бути і private, оскільки нема методів похідного класу, які б потребували доступу до даних класу Distance. Але, якщо виникне потреба в доступі, то його завжди можна буде здійснити.

 

Використання програми 11.5

В функції main() програми оголошені три інтервали. Інтервал alpha дістає значення від користувача, beta ініціалізується набором (11,6.25) і знаком + за замовчуванням, gamma – набором (100,5.5,neg), де neg означає знак -.

Клас DistSign є похідним класу Distance. До нього додане поле sign типу posneg. Поле sign призначене для зберігання знаку інтервалу. Тип posneg визначений в операторі enum і має два можливі значення – pos і neg.

 

Конструктори класу DistSign

Клас DistSign має два конструктори, таких самих, як і клас Distance. Перший не має аргументів, у другого два або три аргументи. Третій, необов’язковий, аргумент другого конструктора – це змінна sign, що приймає значення pos або neg. Ці конструктори дозволяють нам визначити об’єкти типу DistSign різними способами.

Обидва конструктори в класі DistSign викликає відповідні конструктори з класу Distance для встановлення значень футів і дюймів. Вони також встановлюють значення поля sign. Конструктор без аргументів завжди встановлює значення поля sign рівним pos. Другий конструктор встановлює значення поля sign як pos, якщо воно не визначене.

Аргументи ft і in, що передаються з функції main() другому конструктору класу DistSign, просто передаються конструктору класу Distance.

 

Методи класу Distance

Додавання поля sign в клас Distance має значення для обох його методів. Метод getdist() класу DistSign повинен послати запит користувачу про знак інтервалу. Метод showdist() повинен вивести знак інтервалу. Ці методи викликають відповідні методи з класу Distance

Distance::getdist();

Distance::showdist();

Таким чином, ми не дублюємо код, а викликаємо підходящі вже готові методи. Це повністю співпадає з загальною концепцією С++ і принципом повторного використання коду.

 

Ієрархія класів

Досі в прикладах цієї теми ми використовували успадковування тільки для додавання нових можливостей до вже існуючих класів. Тепер розглянемо приклад, де успадковування використовується з іншою метою, як частина первинної розробки програми.

В якості прикладів розглянемо базу даних службовців певної компанії. В ній існує три категорії службовців: менеджери, вчені і робітники. В базі даних зберігаються імена службовців всіх категорій та їх ідентифікаційні номери. В інформації про менеджерів міститься ще й назва їх посади і внески в клуб, в інформації про вчених – кількість публікацій.

Приклад нашої програми починається з опису базового класу employce. Цей клас містить прізвища працівників та їх номери. Він породжує три нових класи: manager, scientist і laborer.

Далі приведено лістінг програми 11.6, яка й реалізує всі ці класи

 #include<iostream.h>

 #include<conio.h>

 #include<stdio.h>

 #include<bios.h>

 const int LEN=80;

 ////////////

 class employce

 {private:

 char name[LEN];

 unsigned long number;

 public:

 void getdata()

 {cout <<”\nВведіть ПІП: “;cin>>name;

 cout <<”\nВведіть номер: “;cin>>number;

 }

 void putdata() const

 {cout<<”\nПІП=”<<name;

 cout<<”\nНомер=”<<number;

 }

 };

 class manager:public employce

 {private:

 char title[LEN];

 double dues;

 public:

 void getdata()

 {employce::getdata();

 cout<<”\nПосада=”;cin>>title;

 cout<<”\nВнески=”;cin>>dues;

 }

 void putdata() const

 {employce::putdata();

 cout<<”\nПосада=”<<title;

 cout<<”\nВнески=”<<dues;

 }

 };

 //////////

 class scientist:public employce

 {private:

 int puts;

 public:

 void getdata()

 { employce::getdata();

 cout<<”\nПублікацій=”;cin>>puts;

 }

 void putdata() const

 { employce::putdata();

 cout<<»\nPublications=»<<puts;

 }

 };

 ////////////

 class laborer:public employce

 {

 };

 //////////

 int main()

 {clrscr();

 manager m1,m2;

 scientist s1;

 laborer l1;

//Vvid

cout<<endl;

cout<<”Менеджер 1\n”;

m1.getdata();

cout<<”Менеджер 2\n”;

m2.getdata();

cout<<”\nВчений 1”;

s1.getdata();

cout<<”\nРобітник 1”;

l1.getdata();

//Вивід

cout<<”\n\nM1”<<endl;

m1.putdata();

cout<<”\n\nM2”<<endl;

m2.putdata();

cout<<”\n\nS1”<<endl;

s1.putdata();

cout<<”\n\nl1”<<endl;

l1.putdata();

 

 

 bioskey(0);

 return 0;

 }

Програма 11.6

 

В функції main() цієї програми оголошені 4 об’єкти різних класів: два об’єкти класу manager, об’єкт класу scientist та об’єкт класу laborer. Вони викликають метод getdata() для одержання даних і метод putdata() для її виведення.

Звичайно, для складнішої програми треба було б розробити масив об’єктів чи якусь іншу структуру.

 

Абстрактний базовий клас

Зауважимо, що ми не визначили об’єкти класу employce. Ми використовуємо його як загальний клас, єдиною метою якого є стати базовим для похідних класів.

Клас laborer виконує ті ж функції, що й клас employce, оскільки не має жодних відмінностей від нього. Може здатися, що клас laborer – зайвий, але, створивши його, ми підкреслили, що всі класи мають одне спільне джерело – клас employce. Крім того, якщо ми захочемо в майбутньому модифікувати клас laborer, нам не треба буде міняти клас employce.

Класи, що використовуються тільки як базові для похідних, наприклад, як employce, інколи неточно називають абстрактними класами, маючи на увазі, що в цього класу немає об’єктів. Однак насправді термін абстрактний має дещо інше значення, ми вже з ним стикалися, знайомлячись з основами ООП в Delphi.

 

Конструктори і функції

Ні в базовому, ні в похідних класах немає конструкторів, тому компілятор, зустрівши вирази типу

manager m1,m2;

використовує конструктор, встановлений за замовчуванням для класу manager, що викликає конструктор класу employce. Методи getdata() і putdata() похідних класів викликають однойменні методи базових класів.

 



Поделиться:


Последнее изменение этой страницы: 2021-12-15; просмотров: 57; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.119.143.4 (0.041 с.)