Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Бичков - Основи сучасного програмування.doc
Скачиваний:
69
Добавлен:
07.03.2016
Размер:
2.67 Mб
Скачать

7.9.6. Ієрархія типів

Похідний клас сам може бути базовим. Наприклад, можна побудувати ієрархію класів:

class student{...};

class programmer:student{...};

class manager:student{...};

class director:manager{...};

Як бачимо з попередніх прикладів, при визначенні конструктора допускається список iнiцiалiзацiї елементів. Він відділяється двокрапкою (:) від заголовка визначення функції та містить елементи даних (базові класи), розділені комами. Для кожного елемента вказується один чи кілька параметрів, які використовуються при iнiцiалiзацiї. Розглянемо два схожих класи з конструкторами. Перший використовує список iнiцiалiзацiї даних, другий – ні.

class XYValue

{int x,y;

public:

XyValue(int_x,int_y):X(_x),y(_y)

{}

};

class XYData

{ int x,y;

XyData(int_x,int_y)

{x=_x;

y=_y;}};

Хоча для більшості елементів даних список iнiцiалiзацiї необов'язковий, він є єдиним методом iнiцiалiзацiї елементів у деяких випадках, наприклад, якщо елемент класу є об'єктом.

7.9.7. Множинне успадкування

Досі ми розглядали просте успадкування, коли похідний клас утворювався з одного базового. У С++ похідний клас можна утворювати з кількох базових. Множинне успадкування відрізняється лише тим, що похідний клас успадковує всі властивості базових.

Нехай А, B, С – деякі класи. Тоді похідний від них клас оголошується так:

class D:public A,public B,public C

{//...};

Аналогічно, як i в простому успадкуванні, відсутність специфікатора доступу за умовчанням інтерпретується закритим специфікатором (private). Наприклад:

class Coord

{protected:

int x,y;

public:

Coord(int_x=0,int_y=0);

Void SetLoc(int_x,int_y);};

Coord::Coord(int_x,int_y)

{SetColor(_x,_y);};

void Coord::SetLoc(int_x,int_y)

{x=_x;

y=_y;}

class Message

{protected:

char msg[MAX_LEN];

public:

void SetMsg(char*_msg)

{strcpy(msg,_msg);}

};

Class MessageXY:public Coord,public Message

{public:

void show();};

void Message XY::show()

{goto(x,y);

printf(msg); }

int main()

{MessageXY greeting;

greeting.SetLoc(10,10);

greeting.SetMsg("Hellow");

greeting.Show();

return 0;};

Із прикладу бачимо, як із двох класів – Coord та Message – утворюється третій – MessageXY. Він успадковує всі поля даних і функції-члени базових класів. Це дозволяє у функції Message XY::show() використовувати поля x, y та msg.

При конфлікті імен (напр., у двох базових класах оголошена функція-член з одним і тим самим іменем) необхідно використовувати операцію розширення області видимості для визначення необхідного нам члена класу.

Припустимо, що у двох базових класах оголошена функція з одним і тим самим ім'ям (func):

class A

{protected:

Int data;

public:

void func(void){}

};

class B{

public:

void func(void){};

class C:public A,public B

{public:

int data;

};

int main(void)

{C c;

c.func() //помилка на етапi компiляцiї

с.data=10;

return 0;}

Вихiд із даної ситуацiї один – розширення областi видимості, тобто виклик функцiї func має здiйснюватися таким чином (у main):

int main(void)

{C c;

с.A::func();

с.B::func();

с.data=10;

return 0;}

Можна описати ще одну функцію, у якій указати, яку з конфліктуючих функцій і коли викликати.

У класі, виведеному із кількох базових, може виникнути необхідність у виклику конструкторів цих класів. Якщо класи А, В, С мають конструктори за умовчанням, то в похідному класі D їх можна викликати таким чином:

class D:public A,public B,public C{

public:

D():A(),B(),C(){ }//...};

Або ж конструктор можна оголосити так:

class D:public A,public B,public C{

public:

D();//...};

і реалізувати його за межами формального опису класу:

D::D():A(),B(),C(){ }

У базових класах можуть бути конструктори з параметрами. Вони викликаються аналогічно, як i у звичайному успадкуванні після двокрапки при визначенні конструктора. Конструктори в похідному класі викликаються в тому порядку, у якому оголошені базові класи. Навіть якщо в конструкторі похідного класу вказати послідовність виклику іншою, відмінною від порядку наступності базових класів, то це не вплине на результат.