Слайд 1МЕТОДИ ОБ'ЄКТНО-ОРІЄНТОВАНОГО ПРОГРАМУВАННЯ - 2007
Бублик В.В.
Кафедра мультимедійних систем, кімн. 204/1
Консультації: вівторок,
середа
15-16 год.
http://emerecu.ukma.kiev.ua/efolio
You are welcome!
Stockholm,
Kungliga Tekniska Högskolan
Слайд 2Тема 6.
Узагальнене програмування
Корисно повторити:
Об'єктне програмування.
Лекція 8. Параметризовані класи
Слайд 3Динамічний поліморфізм
Чи завжди він потрібен?
Слайд 4© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Динамічний поліморфізм
Пізнє зв'язування віртуальних функцій
вимагає
Ієрархії класів
Дотримання дисципліни
стабільного інтерфейсу
нетермінальних класів
Накладних витрат непрямого виклику
Слайд 5© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Поліморфна ієрархія класів
Базовий клас
class Base
{
public:
virtual void vf() {
cout<<"Base::f()"< void g() {
cout<<"Base::g()"<};
Слайд 6© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Поліморфна ієрархія класів
Похідний клас
class Derived:
public Base {
public:
virtual void vf() {
cout<<" Derived ::f()"<};
Слайд 7© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Заміщення при пізньому зв'язуванні
void manipulator(Base
& x){
x.f();
x.g(); }
Base b;
Derived d;
manipulator(b); //Base::f();Base::g()
manipulator(d); //Derived:: f();Base::g()
Слайд 8© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Накладні витрати поліморфізму
x.f(); // виклик віртуальної функції
00401207
mov edx,dword ptr [ebp+8]
0040120A mov eax,dword ptr [edx]
0040120C mov esi,esp
0040120E mov ecx,dword ptr [ebp+8]
00401211 call dword ptr [eax]
00401213 cmp esi,esp
00401215 call __chkesp (00409620)
0040121A
x.g(); // виклик невіртуальної функції
00401700 mov ecx,dword ptr [ebp+8]
00401703 call @ILT+805(Base::g) (0040132a)
00401708
Слайд 9© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Внесення стабільного інтерфейсу
Базовий клас
class NVIBase
{
public:
void vf() {
dovf(); return;}
void g() {
cout<<"Base::g()"<private:
virtual void dovf() {
cout<<"Base::f()"<};
Слайд 10© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Внесення стабільного інтерфейсу
Похідний клас
class NVIDerived:
public NVIBase
{
private:
virtual void dovf() {
cout<<" Derived ::f()"<};
Слайд 11© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Накладні витрати невіртуального інтерфейсу
Без особливих
додаткових накладних витрат: один зайвий виклик невіртуальної інтерфейсної функції
x.vf();
00416E5E mov ecx,dword ptr [x]
00416E61 call NVIBase::vf (415EFBh)
Слайд 12© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Виділення абстрактного нетермінального класу
Базовий клас
class
NVINTBase {
public:
void vf() {
dovf(); return;}
void g() {
cout<<"Base::g()"< virtual ~NVINTBase()=0;
private:
virtual void dovf() {
cout<<"Base::f()"<};
Слайд 13© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Виділення абстрактного нетермінального класу
Похідні класи
class NVITBase: public NVINTBase
{};
class NVITDerived: public NVINTBase {
private:
virtual void dovf() {
cout<<" Derived ::f()"<};
Слайд 14© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Порівняння викликів деструкторів
Виклик невіртуального деструктора
delete nvip;
0043771D mov eax,dword ptr [nvip]
00437720 mov dword ptr [ebp-158h],eax
00437726 mov ecx,dword ptr [ebp-158h]
0043772C push ecx
0043772D call operator delete (41550Fh)
00437732 add esp,4
Слайд 15© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Порівняння викликів деструкторів
Накладні витрати віртуального
деструктора
delete pb;
00437780 mov eax,dword ptr [pb]
00437783 mov dword ptr [ebp-134h],eax
00437789 mov ecx,dword ptr [ebp-134h]
0043778F mov dword ptr [ebp-140h],ecx
00437795 cmp dword ptr [ebp-140h],0
0043779C je main+151h (4377C1h)
0043779E mov esi,esp
004377A0 push 1
004377A2 mov edx,dword ptr [ebp-140h]
004377A8 mov eax,dword ptr [edx]
004377AA mov ecx,dword ptr [ebp-140h]
004377B0 call dword ptr [eax]
004377B2 cmp esi,esp
004377B4 call @ILT+2795(__RTC_CheckEsp) (415AF0h)
004377B9 mov dword ptr [ebp-16Ch],eax
004377BF jmp main+15Bh (4377CBh)
004377C1 mov dword ptr [ebp-16Ch],0
Слайд 16© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Висновок
Повна гнучкість рішень за рахунок
динамічного розпізнавання типу об'єкту при значних затратах як на етапі програмування, так і виконання
Слайд 17© 2006 Бублик В.В. МООП-9. Узагальнене програмування
“Невіртуальна” ієрархія
class Base {
public:
void f()
{cout<<"Base::f()"< void g() {cout<<"Base::g()"<};
class Derived : public Base {
public:
void f() {cout<<" Derived::f()"<// пряме відсилання до базового класу
void g() {Base::g();}
};
Слайд 18© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Раннє зв'язування
void manipulator(Base & x){
x.f();
x.g();
}
Base b;
Derived d;
manipulator(b); //Base::f();Base::g()
manipulator(d); // Base::f();Base::g()
Слайд 19© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Висновок
Раннє зв'язування не забезпечує заміщень:
при підстановці параметром об'єкту похідного класу викликаються функції базового
Слайд 20© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Узагальнений маніпулятор ієрархією класів
template
T>
void manipulator(T & x){
x.f();
x.g(); }
Base b;
Derived d;
manipulator(b); //Base::f();Base::g()
manipulator(d); //Derived:: f();Base::g()
Слайд 21© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Висновок
Шаблон, застосований до ієрархії, доповненої
явним делегуванням, моделює статичний поліморфізм
Слайд 22© 2006 Бублик В.В. МООП-9. Узагальнене програмування
“На городі бузина...”
class ElderBerry // бузина
{
public:
void
f(char a='!', double x=1, bool t=true)
{
cout<<"ElderBerry::f()"< }
void g(char a='?')
{
cout<<"ElderBerry::g()"< }
void goToUncle(); // у Києві
};
Слайд 23© 2006 Бублик В.В. МООП-9. Узагальнене програмування
А де Murgatroyd?
class Murgatroyd
{
public:
void f() {
cout<<"Murgatroyd::f()"< }
void g(ElderBerry & ga=ElderBerry(),
double a=3.14) {
cout<<" ElderBerry::g()"< ga.g();
}
// An exclamation of surprise
int heavensTo(const Murgatroyd &);
};
Слайд 24© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Узагальнена функція
template
void manipulator(T
& x){
x.f();
x.g(); }
ElderBerry u;
Murgatroyd v;
manipulator(u); // ElderBerry::f(), ElderBerry:: g()
manipulator(v); // Murgatroyd ::f(), ElderBerry:: g()
Слайд 25© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Поліморфізм без ієрархії
Методи узагальненого програмування
дозволяють промоделювати статичний поліморфізм не застосовуючи ієрархії класів, а лише їх знайомств за умови узгодженості їх поведінки
Слайд 26© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Висновок
Кожен початківець хоче продемонструвати володіння
успадкуванням (90% випадків)
Віртуальні функції найчастіше вживаються некоректно
Застосовувати динамічний поліморфізм варто лише тоді, коли статичного не вистачає
Узагальнене програмування найпотужніший механізм статичного поліморфізму, але...
Слайд 27Безпечність узагальненого програмування
Наперед невідомо, який саме тип буде підставлено до шаблону:
як гарантувати працездатність за мінімальних вимог до типового параметру? Як уникнути збоїв на етапі виконання?
Слайд 28© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Синтаксичний контроль типів
Успадкування типів
Зведення типів
Примітивність
типів
Індексованість типів
Слайд 29© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Типізація (за Бучем)
Засіб захисту від
використання об’єктів одного класу замість іншого, або принаймні спосіб управління цим використанням.
Слайд 30© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Шаблон з одним параметром
Пробуємо розмістити
значення
Того ж типу Т на новому місці
template
void construct( T*& p, const T& value )
{
p =new T(value);
return;
}
Слайд 31© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Застосування шаблону
void converted( double*& p1,
Base* p2 ) {
Base b;
Derived d;
construct( p1, 2.718 );
construct( p2, b );
construct( p1, 42 );
construct( p1, 42 );
construct( p2, d );
construct( p2, d );
}
Слайд 32© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Результати першої спроби
void converted( double*&
p1, Base* p2 ) {
Base b;
Derived d;
construct( p1, 2.718 );
construct( p2, b );
// construct( p1, 42 ); 42 is int
construct( p1, 42 );
// construct( p2, d ); d is Derived
construct( p2, d );
}
Слайд 33© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Висновок
(з першої спроби)
Надто жорстка умова
на типовий параметр
Слайд 34© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Шаблон з двома параметрами
Пробуємо розмістити
значення типу Т2
на новому місці за указником типу Т1
Як уникнути недопустимих комбінацій типів
template
void construct( T1*& p, const T2& value )
{
p =new T2(value);
return;
}
Слайд 35© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Обмеження на успадкування
template
Base, class Derived>
struct must_have_base
{
~must_have_base()
{
void (*p)(Derived*, Base*) = constraints;
}
private:
static void constraints(Derived* pd, Base* pb)
{
pb=pd;
}
};
Слайд 36© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Шаблон, доповнений перевіркою підтипів
Спроба використати
недопустиму
комбінацію типів діагностується компілятором
template
void construct( T1*& p, const T2& value )
{
must_have_base check;
p =new T2(value);
return;
}
Слайд 37© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Результати другої спроби
void converted( double*&
p1, Base* p2 ) {
Base b;
Derived d;
construct( p1, 2.718 );
construct( p2, b );
// construct( p1, 42 ); 42 is int
// construct( p1, 42 ); не підтип
construct( p2, d ); // ОК d is Derived
construct( p2, d );
}
Слайд 38© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Обмеження на зводимість
template
class Convert>
struct must_be_converted
{
~must_be_converted()
{
void (*p)(Type &, const Convert &) =
constraints;
}
private:
static void constraints(Type & s, const Convert & t)
{
s=t; }
};
Слайд 39© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Шаблон, доповнений перевіркою зведення типів
Спроба
використати недопустиму
комбінацію типів діагностується компілятором
template
void construct( T1*& p, const T2& value )
{
must_be_converted check;
p =new T2(value);
return;
}
Слайд 40© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Результати третьої спроби
void converted( double*&
p1, Base* p2 ) {
Base b;
Derived d;
construct( p1, 2.718 );
construct( p2, b );
construct( p1, 42 ); // ОК 42 converted to double
construct( p1, 42 );
construct( p2, d ); // ОК d is Derived
construct( p2, d );
}
Слайд 41© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Перевірка примітивності типу
template
struct
must_be_POD
{
~must_be_POD()
{
void (*p)() = constraints;
}
private:
static void constraints() {
union{
T T_is_not_POD_type;};
}
};
Слайд 43© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Перевірка індексованості
template
struct must_be_subscriptable
{
~must_be_subscriptable()
{
void
(*p)(const T &) = constraints;
}
private:
static void constraints
(const T& T_is_not_subscriptable) {
sizeof(T_is_not_subscriptable[0]);
}
};
Слайд 44© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Перевірка розмірностей
template
T2>
struct must_have_same_size
{
~must_have_same_size() {
void (*p)() = constraints;
}
private:
static void constraints() {
const int T1_not_same_size_as_T2 =
sizeof(T1) == sizeof(T2);
int i[T1_not_same_size_as_T2];
}
};
Слайд 45© 2006 Бублик В.В. МООП-9. Узагальнене програмування
Висновок
Збалансовуйте застосування успадкувань і шаблонів
Зважено
контролюйте типи, але не вимагайте від них більше, ніж потрібно