Shape::draw()
draw_lines()
класса Shape
, чтобы она выполнила реальную работу, связанную с выводом изображений на экран. Ни “графический движок”, ни класс Shape
не знают, какие виды фигур существуют. В частности, наш “графический движок” (библиотека FLTK и графические средства операционной системы) написан и скомпилирован за много лет до создания наших графических классов! Мы просто определяем конкретные фигуры и вызываем функцию attach()
, чтобы связать их с объектами класса Window
в качестве объектов класса Shape
(функция Window::attach()
получает аргумент типа Shape&
; см. раздел Г.3). Более того, поскольку класс Shape
не знает о наших графических классах, нам не нужно перекомпилировать класс Shape
каждый раз, когда мы хотим определить новый класс графического интерфейса. Shape
vector
; наследование здесь мало может помочь). Однако наследование интерфейса — один из мощных методов проектирования и реализации систем, устойчивых к изменениям. Shape
Shape
или любое изменение в размещении его данных-членов потребует повторной компиляции всех производных классов и их клиентов. Для широко используемых библиотек такая повторная компиляция может оказаться неразрешимой проблемой. Естественно, существуют способы достичь указанных преимуществ и избежать большинства проблем (см. раздел 14.3.5).Задание
К сожалению, мы не можем сформулировать задание, которое выявило бы понимание общих принципов проектирования, поэтому решили сосредоточиться на свойствах языка, поддерживающих объектно-ориентированное программирование.
1. Определите класс B1
vf()
и невиртуальной функцией f()
. Определите эти функции в классе B1
. Реализуйте каждую функцию так, чтобы она выводила свое имя (например, “B1::vf()
”). Сделайте эти функции открытыми. Создайте объект B1
и вызовите каждую из функций.2. Определите класс D1
B1
, и заместите функцию vf()
. Создайте объект класса D1
и вызовите функции vf()
и f()
из него.3. Определите ссылку на объект класса B1
B1&
) и инициализируйте ею только что определенный объект класса D1
. Вызовите функции vf()
и f()
для этой ссылки.4. Теперь определите функцию f()
D1
и повторите пп. 1–3. Объясните результаты.5. Добавьте в класс B1
pvf()
и попытайтесь повторить пп. 1–4. Объясните результат.6. Определите класс D2
D1
, и заместите в нем функцию pvf()
. Создайте объект класса D2
и вызовите из него функции f()
, vf()
и pvf()
.7. Определите класс B2
pvf()
. Определите класс D21
с членом типа string
и функцией-членом, замещающей функцию pvf()
; функция D21::pvf()
должна выводить значение члена типа string
. Определите класс D22
, аналогичный классу D21
, за исключением того, что его член имеет тип int
. Определите функцию f()
, получающую аргумент типа B2&
и вызывающую функцию pvf()
из этого аргумента. Вызовите функцию f()
с аргументами класса D21
и D22
.Контрольные вопросы
1. Что такое предметная область?
2. Назовите цели именования.
3. Что такое имя?
4. Какие возможности предоставляет класс Shape
5. Чем абстрактный класс отличается от других классов?
6. Как создать абстрактный класс?
7. Как управлять доступом?
8. Зачем нужен раздел private
9. Что такое виртуальная функция и чем она отличается от невиртуальных функций?
10. Что такое базовый класс?
11. Как объявляется производный класс?
12. Что мы подразумеваем под схемой объекта?
13. Что можно сделать, чтобы класс было легче тестировать?
14. Что такое диаграмма наследования?
15. В чем заключается разница между защищенными и закрытыми членами класса?
16. К каким членам класса имеют доступ члены производного класса?
17. Чем чисто виртуальная функция отличается от других виртуальных функций?
18. Зачем делать функции-члены виртуальными?