• Like
  • Save
OO Design with C++: 2. Inheritance, part 2
Upcoming SlideShare
Loading in...5
×

Thanks for flagging this SlideShare!

Oops! An error has occurred.

OO Design with C++: 2. Inheritance, part 2

  • 290 views
Published

 

Published in Technology , Business
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
290
On SlideShare
0
From Embeds
0
Number of Embeds
0

Actions

Shares
Downloads
0
Comments
0
Likes
1

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide
  • Public vs. protected interface - two types of clients {part. Meyers1.41}. Containment as "has-a" or "is-implemented-via" relationship {Meyers1.40} Private inheritance - reasons of use instead of containment {Meyers1.42}

Transcript

  • 1. C++ : наследование, часть 2 Дмитрий Штилерман, Рексофт
  • 2. Краткое содержание второй части
    • Public & protected interface .
    • Случаи видимости наследования ( public, protected, private) и их семантика.
    • О тношения “has-a” и “is-implemented-by”.
    • Композиция (aggregation).
    • Делегирование ( delegation) .
    • Изоляция ( insulation ).
  • 3. Интерфейсы и реализация класса
    • Дизайнер класса B в общем случае проектирует два разных интерфейса: public & protected.
    • Public interface - множество всех public members B. Его клиенты - все классы, использующие B.
    • Protected interface - множество всех protected members B . Его клиенты - классы, производные от B.
    • Как насчет п онятия private interface? Private members класса B являются частью его реализации (implementation), а не интерфейса.
  • 4. Public & protected interface - пример class Shape { public: virtual void redraw() = 0; protected: void default_redraw(); }; class Tool { public: void applyTo(Shape* pShape) {/*…*/ pShape->redraw();} }; class Rectangle : public Shape { public: virtual void redraw() {/*…*/ default_redraw();} };
    • Shape:: redraw() - часть public interface . Им могут пользоваться любые классы и функции.
    • Shape::default_redraw() - часть protected interface. Им могут пользоваться только производные классы.
  • 5. Public & protected interface - обозначения
    • I public (B) - class B public interface.
    • I protected (B) - class B protected interface.
    • I(B) - class B complete interface. I(B)  I public (B)  I protected (B)
    • I(B,A) - part of class B interface inherited from its base class A.
    • I(B,*) - part of class B interface inherited from all its base classes.
    • I(B,B) - part of class B interface declared inside B itself (“own” interface). I x (B)  I x (B,*)  I x (B,B)
    • R(B) - class B implementation.
  • 6. Public inheritance class B { public: void f_public(); protected: void f_protected(); }; class D : public B { public: void g_public(); protected: void g_protected(); };
    • I public (D) = I public (B)  I public (D,D)
    • I protected (D) = I protected (B)  I protected (D,D)
    • I(D) = I( B )  I(D,D)
    • I public (B) = {B::f_public()}
    • I protected (B) = {B::f_protected()}
    • I public (D) = {B::f_public(), D::g_public()}
    • I protected (D) = {B::f_protected(), D::g_protected()}
    Public и protected интерфейсы B добавляются в соответствующие интерфейсы D.
  • 7. Protected inheritance class B { public: void f_public(); protected: void f_protected(); }; class D : protected B { public: void g_public(); protected: void g_protected(); };
    • I public (B) = {B::f_public()}
    • I protected (B) = {B::f_protected()}
    • I public (D) = {D::g_public()}
    • I protected (D) = { B::f_public(), B::f_protected(), D::g_protected()}
    • I public (D) = I public (D,D)
    • I protected (D) = I(B)  I protected (D,D)
    • I(D) = I( B )  I(D,D)
    Public и protected интерфейсы B добавляются в protected интерфейс D.
  • 8. Private inheritance class B { public: void f_public(); protected: void f_protected(); }; class D : private B { public: void g_public(); protected: void g_protected(); };
    • I public (B) = {B::f_public()}
    • I protected (B) = {B::f_protected()}
    • I public (D) = {D::g_public()}
    • I protected (D) = {D::g_protected()}
    • I public (D) = I public (D,D)
    • I protected (D) = I protected (D,D)
    • I(D,*) = I( D,B ) = 
    • I(D) = I(D,D)
    • R(D)  I(B) (!!!)
    Public и protected интерфейсы B становятся частью реализации D.
  • 9. Когда какое наследование возможно использовать?
    • Public : когда хотим интерфейсы базового класса раздать всем своим клиентам. I(Derived)  I(Base).
    • Protected : когда хотим интерфейсы базового класса раздать своим производным классам (клиентам protected интерфейса). I protected (Derived)  I(Base).
    • Private : когда хотим воспользоваться интерфейсами базового класса сами, т.е. включить их в нашу реализацию. R(Derived)  I(Base).
  • 10. Почему обычно не нужно использовать наследование, отличное от public?
    • Любое наследование соответствует отношению “is-a”.
    • Отношение “is-a” концептуально (на уровне анализа) является частью интерфейса класса и определяет тип объекта.
    • Изменяя видимость наследования мы меняем видимость отношения “is-a” для клиентов класса .
    • На практике очень редко встречается ситуация, когда видимость отношения “is-a” различна для разных клиентов.
  • 11. Отношение “has-a” - к омпозиция (aggregation) class Caption {…}; class Label {…}; class Button {…}; class MessageBox { Caption m_caption; Label m_label; Button m_buttonOK; Button m_buttonCancel; };
    • Отношение “has-a” на практике всегда реализуется через композицию ( aggregation) . See also: Composite pattern.
    • Отношение “has-a” концептуально отлично от отношения “is-a”.
    • NB: не стоит реализовывать отношение “has-a” через public data members! Лучше делать это через accessor methods , внимательно обдумывая интерфейс.
  • 12. Отношени е “is-implemented-by” - делегирование (delegation)
    • Концептуально отношение “is-implemented-by” всегда является частью реализации.
    • Толкования слова “делегирование” из словаря: “передача прав и ответственности подчиненному”, “перед а ча полномочий” .
    • Делегирование - частный случай использования.
    • Что происходит с интерфейсами?
      • В случае делегирования на уровне public или protected методов мы делаем так, что I(A)  I public (B), но при этом B не является базовым классом A.
      • В случае делегирования на уровне private методов делегирование является частью реализации.
    class A { B m_b; void f() {m_b.f();} void g() {m_b.g();} }; class B { public: void f() {…} void g() {…} };
  • 13. И золяция ( insulation )
    • Изоляция ( insulation) - разновидность инкапсуляции, когда клиенты класса полностью изолированы от деталей реализации.
    • Изоляция - разновидность композиции (с точки зрения структуры).
    • Синонимы: метафора “handle-body”, метафора “letter-envelope”.
    • John Lakos, “Large-Scale C+ Software Design”
    // Файл gadget.h class GadgetImpl; class Gadget { private: GadgetImpl* m_pImpl; public: Gadget(); void f(); }; // Файл gadget.cpp #include “gadget.h” class GadgetImpl { public: void f() {…} }; Gadget::Gadget() {m_pImpl = new GadgetImpl;} void Gadget::f() {m_pImpl->f();}
  • 14. P rivate inheritance как инкапсуляция базового класса
    • Хотим использовать protected интерфейс класса B  в ынуждены от него наследовать.
    • Отношение “is-implemented-by” есть часть реализации  наследование д.б. private .
    • Вопрос: Зачем такое извращение м.б. нужно? Ответ: Когда мы хотим сделать частью реализации сам базовый класс!
    class A : private B { void f() {B::f();} void g() {B::g();} }; class B { public: void f() {…} protected: void g() {…} };
  • 15. P rivate inheritance как упаковка общей части реализации
    • Хотим абстрагировать для нескольких наших классов их общую реализацию, выделив ее в отдельный класс.
    • Не хотим, чтобы ей пользовался кто-то другой.
    • По каким-то причинам не хотим или не можем использовать изоляцию.
    • Часто встречающаяся уважительная причина - реализация шаблонов .
    class GadgetBase { protected: GadgetBase(); void f() {/* Очень умный алгоритм */} }; template<class T> class Gadget : private GadgetBase { public: void f() {GadgetBase::f();} };
  • 16. Подведение итогов
    • Основной вопрос философии
    • Что хотел сказать автор своим дизайном?
    • Правила правой руки
    • Отношение “is-a”: public inheritance
    • Отношение “has-a”: aggregation
    • Отношение “is-implemented-by”:
      • Изоляция не нужна или невозможна: aggregation
      • Изоляция нужна и возможна: insulation
      • Желательна упаковка общей реализации нескольких классов: private inheritance
  • 17. Продолжение в следующей серии
    • Множественное наследование .
    • Какое оно бывает?
    • Что оно значит?
    • Как с ним бороться?