Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
О.О.П / ооп / 18. Об'єктно-орієнтоване програмування, л.5.5 - 5.8.ppt
Скачиваний:
26
Добавлен:
30.05.2020
Размер:
3.38 Mб
Скачать

Множинне

спадкоємство

Мова C++ допускає спадкоємство класу від більш, ніж одного базового класу

Таке спадкоємство називають множинним

При цьому породжений клас може володіти властивостями відразу декількох батьківських класів

Наприклад, клас може реалізовувати відразу декілька інтерфейсів або использвоать декілька реалізацій

IDrawable

CFillable

IShape

CText

CRectangle CLine

// інтерфейс об'єктів, які можна намалювати

class IDrawable

{

public:

virtual void Draw()const = 0; virtual ~IDrawable(){}

};

// інтерфейс геометричних фігур

class IShape : public IDrawable

{

};

class CText : public

IDrawable

{

public:

virtual void Draw()const;

};

class CLine : public IShape

{

public:

virtual void Draw()const;

};

// клас об'єктів, що мають заливку class CFillable

{

public:

void SetFillColor(int fillColor); int GetFillColor()const;

virtual ~CFillable(){} private:

int m_fillColor;

};

class CRectangle : public IShape, public

CFillable

{

public:

virtual void Draw()const;

};

Проблеми, що виникають при множинному спадкоємстві

При всій своїй потужності і гнучкості множинне спадкоємство може з'явитися джерелом проблем

Яскравим прикладом є т.з. «ромбоподібне спадкоємство» (батьківські класи об'єкту успадковуються від одного базового класу)

У деяких ЯП множинне спадкоємство заборонене

Породжуваний клас може успадковуватися лише від одного базового класу і реалізовувати декілька інтерфейсів - множинне інтерфейсне спадкоємство

CAnimal

CMammal

CWingedAnimal

CBat

//Животное class CAnimal

{

public:

virtual void Eat(){}

};

//Млекопитающее

class CMammal : public CAnimal

{

public:

virtual void FeedWithMilk(){}

};

// Животное с крыльями

class CWingedAnimal : public CAnimal

{

public:

virtual void Fly(){}

};

// Летучая мышь class CBat

: public CMammal

, public CWingedAnimal

{

};

int main(int argc, char * argv[])

{

CBat bat;

//error: ambiguous access of 'Eat' bat.Eat();

//как ест летучая мышь:

//как млекопитающее? bat.CMammal::Eat();

//или как крылатое животное? bat.CWingedAnimal::Eat();

return 0;

}

Можливе вирішення даної проблеми - віртуальне спадкоємство

Проблема ромбоподібного спадкоємства полягає в тому, що клас CBat містить в собі дві копії даних об'єкту CAnimal

Копія, успадкована від CmammalКопія, успадкована від CWingedAnimal

Віртуальне спадкоємство у ряді випадків дозволяє вирішити проблеми неоднозначності, що виникають при множинному спадкоємстві

При віртуальному спадкоємстві відбувається об'єднання декількох успадкованих екземплярів загального предка в один

Базовий клас, успадкований безліч, визначається віртуальним за допомогою ключового слова virtual

//Тварина class CAnimal

{

public:

virtual void Eat(){}

};

//Ссавець

class CMammal

: public virtual CAnimal

{

public:

virtual void FeedWithMilk(){}

};

// Тварина з крилами class CWingedAnimal

: public virtual CAnimal

{

public:

virtual void Fly(){}

};

// Кажан class CBat

: public CMammal

, public CWingedAnimal

{

};

int main(int argc, char * argv[])

{

CBat bat;

// Теперь нормально bat.Eat();

return 0;

}

Обмеження віртуального спадкоємства

Класи-предки не можуть одночасно перезавантажувати одні і ті ж методи свого батька

У нашому випадку - не можна перевизначати метод Eat() одночасно і в CMammal, і в CWingedAnimal - буде помилка компіляції

В разі перевизначення цього методу в одному з класів компілятор видасть попередження

Коли множинне спадкоємство може бути корисним

При акуратному використанні множинне спадкоємство може бути вельми ефективним

Створення класу, що використовує декілька реалізацій

Широко застосовується в бібліотеках ATL і WTL

Створення класу, що реалізовує декілька інтерфейсів

Основне правило - уникайте

ромбоподібного спадкоємства