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

996 views

Published on

Published in: Technology
0 Comments
1 Like
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
996
On SlideShare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
0
Comments
0
Likes
1
Embeds 0
No embeds

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}
  • OO Design with C++: 1. Inheritance, part 1

    1. 1. C++ : наследование, часть 1 Дмитрий Штилерман, Рексофт
    2. 2. Краткое содержание первой части <ul><li>Открытое наследование (public inheritance) как отношение &quot;is-a” . </li></ul><ul><li>Иерархическая и другие виды классификаций. </li></ul><ul><li>Отношение “is-a” - возможные ошибки проектирования и способы их предотвращения. </li></ul><ul><li>Наследование интерфейса и наследование реализации. </li></ul><ul><li>Применение виртуальных методов. </li></ul>
    3. 3. Открытое наследование (public inheritance) - отношение &quot;is-a&quot; class Person {}; class Student : public Person {}; class Teacher : public Person {}; void f(Person&) {…} void g() { Student s; Teacher t; f(s); f(t); } Отношение “is-a” организует объекты в виде иерархической классификации.
    4. 4. Виды классификаций <ul><li>А какие бывают классификации? </li></ul><ul><li>Иерархическая </li></ul><ul><li>Комбинативная </li></ul><ul><li>Параметрическая </li></ul><ul><li>Смешанные (на разных уровнях - разные виды) </li></ul><ul><li>А.А.Любищев, «О форме естественной системы организмов» </li></ul>
    5. 5. Виды классификаций - иерархическая <ul><li>К лассы находятся в отношении “надкласс-подкласс”. </li></ul><ul><li>Каждый класс имеет характерные признаки, присущие только ему из всех его «братьев». </li></ul><ul><li>Пример: систематика живых организмов. </li></ul><ul><li>Выбор признаков определяет стратегию классификации. </li></ul><ul><li>Примеры стратегий: </li></ul><ul><ul><li>Филогенетическая (общность определяется происхождением). </li></ul></ul><ul><ul><li>Морфологическая (общность определяется формой). </li></ul></ul>Млекопитающие Выкармливают детенышей молоком Приматы Всеядные, зубная система гетеродонтная, глаза направлены вперед Высшие обезьяны Нет хвоста
    6. 6. Виды классификаций - комбинативная <ul><li>Принадлежность к классу определяется значения ми некоторых признаков. </li></ul><ul><li>Признаки могут сочетаться произвольным образом . </li></ul><ul><li>Пример: матрица Boston Consulting Group для оценки компаний . </li></ul>Высокие темпы роста Знаки вопроса Звезды Дойные коровы Собаки Низ кие темпы роста Большая доля рынка Малая доля рынка ???
    7. 7. Виды классификаций - параметрическая <ul><li>Принадлежность к классу определяется значениями немногих существенных параметров. </li></ul><ul><li>Большинство характеристик объекта коррелирует с существенными параметрами. </li></ul><ul><li>Пример: периодическая система элементов (существенный параметр - атомный вес) . </li></ul>
    8. 8. Отношение “is-a” - как можно ошибиться? (1) class StupidBird {public: virtual void fly() = 0;}; class StupidEagle : public StupidBird {public: virtual void fly();}; class StupidPenguin : public StupidBird {public: virtual void fly();}; Пингвины не умеют летать. Как мы собираемся реализовывать Stupid Penguin::fly()?
    9. 9. Отношение “is-a” - как можно ошибиться? (2) class Rectangle { public: int getHeight() const; virtual void setHeight(int); int getWidth() const; virtual void setWidth(int); }; void RectangleTest(Rectangle& r) { r.setHeight(4); r.setWidth(5); int S = r.getHeight()*r.getWidth(); assert(S==20); } class Square : public Rectangle { public: void setHeight(int h) { Rectangle::setHeight(h); Rectangle::setWidth(h); } void setWidth(int w) { Rectangle::setWidth(w); Rectangle::setHeight(w); } };
    10. 10. Отношение “is-a” - как не ошибиться? <ul><li>Важно поведение объекта, а не классификация, действующая в предметной области. </li></ul><ul><li>Все, верное для базового класса, должно быть верным и для производного. </li></ul><ul><li>Интерфейс класса должен быть полным и минимальным. </li></ul>
    11. 11. Отношение “is-a” - The Liskov Substitution Principle <ul><li>If for each object o 1 of type S there is an object o 2 of type T such that for all programs P defined in terms of T, the behavior of P is unchanged when o 1 is substituted for o 2 then S is a subtype of T. </li></ul><ul><li>Barbara Liskov, “Data Abstraction & Hierarchy” </li></ul><ul><li>An object-oriented function that uses pointers or references to a base class must be able to use objects of derived classes without knowing it. </li></ul><ul><li>Robert C. Martin, “The Liskov Substitution Principle” </li></ul>
    12. 12. Отношение “is-a” - как исправить ошибку? (1) В рамках задачи неверно утверждение «все птицы умеют летать». Значит, неправильно делать fly() методом Bird. Решение из обычного орнитологического определителя: дополнительная теза-антитеза «летает - не летает».
    13. 13. Отношение “is-a” - как исправить ошибку? (2) class Rectangular { public: virtual int getHeight() const = 0; virtual int getWidth() const = 0; }; class Square : public Rectangular { public: virtual int getHeight() const; virtual int getWidth() const; void setSide(int s); }; class Rectangle : public Rectangular { public: virtual int getHeight() const; virtual int getWidth() const; void setHeight(int h); void setWidth(int w); };
    14. 14. Наследование интерфейса и наследование реализации <ul><li>При проектировании базовых и производных классов важно различать наследование интерфейса и реализации. </li></ul><ul><li>Можно наследовать то и другое как по отдельности, так и вместе. </li></ul><ul><li>Конкретная семантика наследования естественно определяется типом метода. Метод м.б. чисто виртуальный, виртуальный, невиртуальный. </li></ul>
    15. 15. Наследование интерфейса class Shape {public: virtual void draw() = 0;}; class Circle : public Shape {public: virtual void draw();}; class Rectangle : public Shape {public: virtual void draw();}; <ul><li>Каждая фигура должна уметь себя нарисовать, следовательно метод draw() должен входить в интерфейс Shape . </li></ul><ul><li>Невозможно нарисовать «фигуру вообще», следовательно Shape::draw() не может иметь реализации. </li></ul><ul><li>Pure virtual function </li></ul>
    16. 16. Наследование интерфейса и обязательной реализации class Shape { public: virtual void draw() = 0; virtual void erase() = 0; bool getVisible() const {return m_bVisible;} void setVisible(bool bVisible) { m_bVisible = bVisible; if(m_bVisible) draw(); else erase(); } private: bool m_bVisible; }; <ul><li>Каждую фигуру можно показать или спрятать, используя метод setVisible() . </li></ul><ul><li>Протокол, по которому работает метод setVisible() , должен быть одним и тем же для всех производных классов. </li></ul><ul><li>Non-virtual function </li></ul><ul><li>See also: Template Method pattern </li></ul>
    17. 17. Наследование интерфейса и реализации по умолчанию (1) class Shape { public: virtual void draw() = 0; virtual void erase() = 0; virtual void redraw() { /* Простейший способ/ erase(); draw(); } }; class Sprite : public Shape { public: virtual void redraw() {/* Оптимизированный способ*/} }; <ul><li>Изображение каждой фигуры можно обновить, используя метод redraw() . </li></ul><ul><li>Существует простейший всегда работающий способ перерисовки. </li></ul><ul><li>Для конкретных производных классов может существовать лучший (например, более быстрый) способ перерисовки. </li></ul><ul><li>Virtual function </li></ul>
    18. 18. Наследование интерфейса и реализации по умолчанию (2) class Shape { public: virtual void redraw() = 0; protected: void default_redraw() {erase(); draw();} }; class Rectangle : public Shape { public: virtual void redraw() {default_redraw();} }; class Sprite : public Shape { public: virtual void redraw() {/*Оптимизированный способ*/} }; <ul><li>Изображение каждой фигуры можно обновить, используя метод redraw() . </li></ul><ul><li>Существует способ перерисовки, работающий часто, но не всегда . </li></ul><ul><li>Каждый производный класс обязан реализовать redraw() , возможно используя реализацию по умолчанию. </li></ul><ul><li>Pure virtual function & Protected non-virtual function </li></ul>
    19. 19. Продолжение в следующей серии <ul><li>Public & protected interface . </li></ul><ul><li>Случаи видимости наследования ( public, protected, private) и их семантика. </li></ul><ul><li>О тношения “has-a” и “is-implemented-by”. </li></ul><ul><li>Композиция (aggregation). </li></ul><ul><li>Делегирование ( delegation) . </li></ul><ul><li>Изоляция ( insulation ). </li></ul>

    ×