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

Like this? Share it with your network

Share
  • 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
620
On Slideshare
619
From Embeds
1
Number of Embeds
1

Actions

Shares
Downloads
0
Comments
0
Likes
1

Embeds 1

http://www.slideshare.net 1

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. Продолжение в следующей серии
    • Множественное наследование .
    • Какое оно бывает?
    • Что оно значит?
    • Как с ним бороться?