- •Що таке композиція?
- •class CPoint
- •// Колесо
- •// Слайд class CSlide
- •Що таке
- •Термінологія
- •Тварина
- •Варіанти
- •Публічне (відкрите) спадкоємство
- •class CPerson
- •Публічне спадкоємство як
- •CShape
- •CPoint
- •Приватне (закрите) спадкоємство
- •class CIntArray
- •Композиція - переважна
- •class CIntArray
- •Захищене
- •class CIntArray
- •Відмінності між захищеним і відкритим
- •Типи спадкоємства в інших мовах
- •Порядок виклику конструкторів
- •Конструктор класу CEmployee (службовець) оголошений захищеним, аби не допустити безглузде створення абстрактних «службовців»
- •Порядок виклику деструкторів
- •class CTable
- •Перевантаження
- •class CBase
- •Завдання - ієрархія геометричних фігур
- •class CShape
- •int main(int argc, char * argv[])
- •void PrintShapeArea(CShape const& shape)
- •У чому ж проблема?
- •Віртуальні методи
- •class CShape
- •void PrintShapeArea(CShape const& shape)
- •Особливості реалізації віртуальних функцій в
- •Віртуальний
- •class CBase
- •class CBase
- •Підводимо підсумки
- •Абстрактні класи
- •class CShape
- •Інтерфейс
- •class IShape
- •Приведення типів
- •Оператор
- •class CAnimal
- •CMammal const& MakeMammal(CAnimal const & animal)
- •Не зловживайте
- •class CAnimal
- •Множинне
- •IDrawable
- •// інтерфейс об'єктів, які можна намалювати
- •Проблеми, що виникають при множинному спадкоємстві
- •CAnimal
- •//Животное class CAnimal
- •Можливе вирішення даної проблеми - віртуальне спадкоємство
- •//Тварина class CAnimal
- •Обмеження віртуального спадкоємства
- •Коли множинне спадкоємство може бути корисним
- •Переваги використання спадкоємства
- •Спадкоємство і питання проектування
Множинне
спадкоємство
Мова 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
Створення класу, що реалізовує декілька інтерфейсів
Основне правило - уникайте
ромбоподібного спадкоємства