Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу)


НазваІнтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу)
Дата конвертації02.05.2013
Розмір445 b.
ТипПрезентации





Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу)

  • Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу)



Інтерфейсні функції не варто перевизначати в похідних класах

  • Інтерфейсні функції не варто перевизначати в похідних класах



Віртуальні функції краще всього закрити похідні класи налагоджують власну реалізацію закритої, а значить невидимої клієнту, частини базового класу virtual int do_area() const;

  • Віртуальні функції краще всього закрити похідні класи налагоджують власну реалізацію закритої, а значить невидимої клієнту, частини базового класу virtual int do_area() const;



Віртуальні функції можуть бути захищеними похідні класи використовують реалізацію базового класу virtual int do_a() const; virtual int& do_a();

  • Віртуальні функції можуть бути захищеними похідні класи використовують реалізацію базового класу virtual int do_a() const; virtual int& do_a();



Правило термінальності: Нетермінальні класи мають бути абстрактними

  • Правило термінальності: Нетермінальні класи мають бути абстрактними

  • Rectangle a(10,20);

  • Square s(30);

  • a = s;

  • Чи став а квадратом?



// Інтерфейс прямокутників

  • // Інтерфейс прямокутників

  • class IRectangle

  • {

  • public:

  • int& a();

  • int& b();

  • const int& a() const;

  • const int& b() const;

  • int area() const;



// реалізація прямокутників

  • // реалізація прямокутників

  • // для наступного налагодження

  • private:

  • virtual int& do_a()=0;

  • virtual const int& do_a() const=0;

  • virtual int& do_b()=0;

  • virtual const int& do_b() const=0;

  • virtual int do_area() const=0;

  • };



class TRectangle: public IRectangle

  • class TRectangle: public IRectangle

  • {

  • public:

  • TRectangle (unsigned int a, int b):_a(a),_b(b){};

  • private:

  • int _a, _b;

  • virtual int& do_a();

  • virtual const int& do_a() const;

  • virtual int& do_b();

  • virtual const int& do_b() const;

  • virtual int do_area() const;

  • };



class TSquare: public IRectangle

  • class TSquare: public IRectangle

  • {

  • public:

  • TSquare(int x):_a(x){}

  • private:

  • int _a;

  • virtual int& do_a():

  • virtual const int& do_a() const;

  • virtual int& do_b();

  • virtual const int& do_b() const;

  • virtual int do_area() const;

  • };



IRectangle *ipr = new TRectangle(10,20);

  • IRectangle *ipr = new TRectangle(10,20);

  • increase_a(*ipr,2);

  • increase_b(*ipr,3);

  • cout<a()<<','<b()<

  • ipr = new TSquare(10);

  • increase_a(*ipr,2);

  • increase_b(*ipr,3);

  • cout<a()<<','<b()<



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

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



Що станеться, якщо патерн NVI застосувати до деструктора? − В тілі деструктора базового класу об'єкти похідних класів вже не існують

  • Що станеться, якщо патерн NVI застосувати до деструктора? − В тілі деструктора базового класу об'єкти похідних класів вже не існують

  • Чому деструктор базового класу мусить бути віртуальним? − Для видалення об'єктів похідних класів при використанні стандартного базового інтерфейсу



class Base

  • class Base

  • {

  • public:

  • Base(int n):_p( new double[n] ){};

  • ~Base() {delete _p;}

  • virtual double * showp() {return _p;}

  • private:

  • double * _p;

  • };



class Derived: public Base

  • class Derived: public Base

  • {

  • public:

  • Derived(int n, int m):

  • Base(n),_q( new double [m]){}

  • ~Derived(){delete _q;}

  • virtual double * showp(){return _q;}

  • private:

  • double * _q;

  • };



Base * pbase = new Derived(10,20);

  • Base * pbase = new Derived(10,20);

  • double * p1=pbase->DBase::showp();

  • double * p2=pbase->showp();

  • cout<

  • // Видалиться лише _p

  • // _q залишиться сміттям

  • delete pbase;

  • cout<



class Base

  • class Base

  • {

  • public:

  • Base(int n):_p( new double[n] ){};

  • // деструктор відкритий віртуальний

  • virtual ~Base() {delete _p;}

  • virtual double * showp() {return _p;}

  • private:

  • double * _p;

  • };



Деструктор базового класу має бути або віртуальним відкритим або невіртуальним захищеним

  • Деструктор базового класу має бути або віртуальним відкритим або невіртуальним захищеним

  • Питання: Для чого захищати деструктор, якщо базовий клас абстрактний?



Стабільний спільний інтерфейс об'єднує різні реалізації базового класу, наприклад, стеку

  • Стабільний спільний інтерфейс об'єднує різні реалізації базового класу, наприклад, стеку



template

  • template

  • class Stack

  • {

  • public:

  • bool empty() const{return doEmpty();}

  • const StackElem& top() const { return doTop();}

  • void pop() {doPop();}

  • void push (const StackElem& el){doPush(el);}

  • size_t size() const {return doSize();}

  • virtual ~Stack(){};



private:

  • private:

  • virtual bool doEmpty() const =0;

  • virtual const StackElem& doTop() const = 0;

  • virtual void doPop() = 0;

  • virtual void doPush (const StackElem&) =0;

  • virtual size_t doSize() const =0;

  • };



Допускає різні реалізації:

  • Допускає різні реалізації:

  • Stack може бути

    • StackDerivedArray
    • StackAggregatingArray
    • StackOnList
  • Забезпечує reuse клієнтів, які використовують цей абстрактний клас як інтерфейс





Що дасть нам спроба нового застосування інтерфейсу класу Stack або реалізації класу StackAggregatingArray в класі PeekBackStackAggregatingArray?

  • Що дасть нам спроба нового застосування інтерфейсу класу Stack або реалізації класу StackAggregatingArray в класі PeekBackStackAggregatingArray?



PeekBackStackAggregatingArray може використовувати реалізацію StackAggregatingArray

  • PeekBackStackAggregatingArray може використовувати реалізацію StackAggregatingArray



Неможливий

  • Неможливий

  • Stack * ps = new PeekBackStackAggregatingArray(20);

  • Цікаве застосування: використати підглядання для виводу вмісту стеку. Але ps не знає функції підглядання, тому з ним все рівно не можна працювати як зі стеком з підгляданням. Так само нічого не дасть спроба використати StackAggregatingArray



Порушено правило нетермінальності

  • Порушено правило нетермінальності

  • Потрібне віртуальне успадкування (проаналізуйте попередження компілятора)



Так само неможливо застосувати підглядання до звичайного стеку

  • Так само неможливо застосувати підглядання до звичайного стеку

  • Два джерела одних і тих же контрактних зобов'язань (кратне успадкування із спільного класу)





// Кандидат в базові класи

  • // Кандидат в базові класи

  • class Person

  • {

  • public:

  • Person(const string& name):_name(name){};

  • string& name(){return _name;}

  • private:

  • string _name;

  • };



// Перший похідний клас

  • // Перший похідний клас

  • class Student: public Person

  • {

  • public:

  • Student(const string& name):Person(name){};

  • int& note(){return _note;}

  • private:

  • int _note;

  • };



// Перший похідний клас

  • // Перший похідний клас

  • class Retiree: public Person

  • {

  • public:

  • Retiree(const string& name):Person(name){};

  • int& pension(){return _pension;}

  • private:

  • int _pension;

  • };



Student good(“Кибальчиш“, 95);

  • Student good(“Кибальчиш“, 95);

  • Student bad(“Плохиш“, 60);

  • Person * p1 =&good;

  • Person * p2 =&bad;

  • // Плохиш законно став відмінником

  • *p1 = *p2;

  • cout<

  • // Студент Плохиш має рейтинг 95



Retiree retiree(“Дідусь“, 1000);

  • Retiree retiree(“Дідусь“, 1000);

  • Person * p3 =&retiree;

  • // А тепер ще й став Плохиш

  • // підвищеним стипендіатом

  • *p3 = *p2;

  • cout<

  • // Громадянину Плохишу призначене

  • // щомісячне утримання в 1000 грн



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

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

  • virtual VPerson& VPerson::

  • operator=(const VPerson& p)

  • {

  • _name = p.name();

  • return *this;

  • }



Через невідповідність параметру операція присвоєння в похідному класі

  • Через невідповідність параметру операція присвоєння в похідному класі

  • virtual VStudent& VStudent ::

  • operator=(const VStudent & p);

  • не зможе замістити присвоєння в базовому класі

  • virtual VPerson& VPerson::

  • operator=(const VPerson& p);



// Віртуальне нетипізоване присвоєння

  • // Віртуальне нетипізоване присвоєння

  • // реалізується через додаткове присвоєння

  • // і небезпечне перетворення типів

  • virtual VStudent& VStudent ::

  • operator=(const VPerson & p)

  • {

  • VStudent vs = dynamic_cast(p);

  • *this = vs;

  • return *this;

  • }



// Невіртуальне присвоєння.

  • // Невіртуальне присвоєння.

  • // Його можна розмістити в закритій частині

  • VStudent& VStudent ::

  • operator=(const VStudent& p)

  • {

  • name()=p.name();

  • note()=p.note();

  • return *this;

  • }



Student good(“Кибальчиш“, 95);

  • Student good(“Кибальчиш“, 95);

  • Student bad(“Плохиш“, 60);

  • Person * p1 =&good;

  • Person * p2 =&bad;

  • // Тепер Плохиш не пройде

  • *p1 = *p2;

  • cout<

  • // Студент Плохиш має рейтинг 60



Retiree retiree(“Дідусь“, 1000);

  • Retiree retiree(“Дідусь“, 1000);

  • Person * p3 =&retiree;

  • // Компілятор візьме віртуальне присвоєння

  • // пенсіонерів, бо *p3 має тип Retiree

  • // і спробує перетворити студента *p2

  • // на пенсіонера: аварія

  • *p3 = *p2;



Перевіряти тип значення перед перетворенням:

  • Перевіряти тип значення перед перетворенням:

  • Для чого тоді поліморфізм?

  • Віддавайте перевагу простим рішенням



Закрити присвоєння в базовому класі, але клас конкретний і ця заборона неприйнятна

  • Закрити присвоєння в базовому класі, але клас конкретний і ця заборона неприйнятна

  • Person x, y;

  • x=y; // недоступний оператор



Як заборонити успадкування з термінального класу? − Закрити конструктор

  • Як заборонити успадкування з термінального класу? − Закрити конструктор

  • Як створювати об'єкти класу з закриттим конструктором? − Клонуванням



// Клас без похідних класів

  • // Клас без похідних класів

  • class Terminal {

  • public:

  • static Terminal *clone ();

  • static Terminal *clone (const Terminal &);

  • private:

  • Terminal();

  • Terminal(const Terminal &);

  • };



// Псевдоконструктори

  • // Псевдоконструктори

  • Terminal * Terminal:: clone ()

  • {

  • return new Terminal ();

  • }

  • Terminal * Terminal:: clone(const Terminal & a);

  • {

  • return new Terminal (a);

  • };





Liskov Substitution Principle

  • Liskov Substitution Principle

  • При відкритому успадкуванні всі контрактні зобов'язання базового класу повинні виконуватися похідним класом, для чого всі заміщення віртуальних функцій не повинні вимагати більше або обіцяти менше ніж їх базові версії



Абстрактний клас простіший конкретного, бо може містити менше реалізації або зовсім її не мати

  • Абстрактний клас простіший конкретного, бо може містити менше реалізації або зовсім її не мати

  • Стандартний прийом абстрагування класу:

  • Чисто віртуальний деструктор

  • virtual ~AClass() = 0;

  • Реалізацію він мусить мати, але інстанціонування класу неможливе



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

  • Застосування позакласних функцій замість членів класу підвищує рівень інкапсуляції, оскільки позакласна функція має обмежений доступ до внутрішньої частини класу



Оператори =, ->, [] і () мусять бути членами класу

  • Оператори =, ->, [] і () мусять бути членами класу

  • Не мусять бути членами класу

  • Операції з обмеженнями на лівий аргумент, наприклад << або >>

  • Операції, що вимагають перетворень типу у лівому аргументі

  • Функції, для реалізації яких досить відкритого інтерфейсу класу

  • Якщо позакласна функція вимагає віртуальної поведінки, то реалізуйте її через додаткову віртуальну функцію



template

  • template

  • class Stack

  • {

  • public:

  • ostream& show(ostream& os) const {

  • return doShow(os);}

  • private:

  • virtual ostream& doShow(ostream& os) const

  • {

  • cout<<"Nothing to show"<

  • return os;

  • }

  • };



template

  • template

  • class PeekBackStackAggregatingArray

  • public StackAggregatingArray,

  • public PeekBackStack

  • {

  • private:

  • virtual bool doPeekback(int i, Elem& elem) const;

  • virtual ostream& doShow(ostream& os) const

  • {

  • return os<<*this<

  • }

  • };



template

  • template

  • ostream& operator<<(ostream& os,

  • const PeekBackStackAggregatingArray& pbst)

  • {

  • os<<"Content of a stack:";

  • char c, space=' ';

  • for (int i=0; pbst.peekback(i,c);++i)

  • {

  • os<

  • }

  • os<

  • }



template

  • template

  • void show(Stack& s)

  • {

  • PeekBackStackAggregatingArray pbs (s.size());

  • while(!ps->empty())

  • {

  • char c = s.top();

  • s.pop();

  • pbs.push(c);

  • }

  • cout<

  • }



Віддавайте перевагу простим рішенням

  • Віддавайте перевагу простим рішенням

  • Будуючи ієрархії, слідкуйте за дотриманням контрактних зобов'язань: не завжди квадрат поводиться як прямокутник

  • Уникайте конкретних базових класів: пам'ятайте про Плохиша

  • Не бійтесь утиліт



Схожі:

Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconІнформація про минуле може змінюватися від ходу до ходу Стратегії гравця2 Стратегії гравця2 B1: вибрати y=1, незалежно від 1 ходу гравця 1
Узагальненням матричних ігор з нульовою сумою є позиційні ігри (або ігри в розгорнутій формі )
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconРозрахунок ходу промінів за допомогою еом
Розрахунок ходу променів через центровану оптичну систему, що складається зі сферичних, плоских і асферичних поверхонь
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconЛекція 3 Лекція 3
Похідні імідазолу та імідазоліну: способи одержання, властивості, аналіз, застосування. Лікарські засоби похідні триазолу, піридину....
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconУ будинок курця не зайде лиходій; у будинок курця не зайде лиходій
В нашій країні курить дві третини чоловіків і кожна п’ята жінка, що вдвічі більше, ніж в цивілізованому суспільстві. Так багато,...
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconЛогічні функції
Використати на повну потужність всі доступні вбудовані функції у формулах допомагають саме логічні функції. Вони займають особливе...
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconСпадкування, похідні класи
Спадкування це один з основних принципів об'єктно-орієнтованого програмування, який дозволяє створювати об'єкти, що спадкують свої...
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconВсі функції консольного виведення інформації можна поділити на шість груп: Всі функції консольного виведення інформації можна поділити на шість груп
Всі функції консольного виведення інформації можна поділити на шість груп: встановлення заданого текстового режиму
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconМожливості міжнародного співробітництва
...
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconРозкладання многочлена на множники
Винести спільний множник за дужки означає поділити кожен член многочлена на спільний множник
Інтерфейсні функції відкриті невіртуальні: всі похідні класи використовують спільний інтерфейс (ніхто не зайде з чорного ходу) iconПравила утворення та обчислення виразів: Правило пріоритетів операцій. Спочатку виконуються операції вищого пріоритету: обчислюються аргументи і всі функції
Він може містити числа, змінні, функції, з'єднані символами арифметичних операцій

Додайте кнопку на своєму сайті:
dok.znaimo.com.ua


База даних захищена авторським правом ©dok.znaimo.com.ua 2013
звернутися до адміністрації
dok.znaimo.com.ua
Головна сторінка