Шрифт:
class B { // абстрактный базовый класс
public:
virtual void f=0; // чисто виртуальная функция
virtual void g=0;
};
B b; // ошибка: класс B — абстрактный
Интересное обозначение
=0
указывает на то, что виртуальные функции B::f
и B::g
являются чистыми, т.е. они должны быть замещены в каком-то производном классе. Поскольку класс B содержит чисто виртуальную функцию, мы не можем создать объект этого класса. Замещение чисто виртуальных функций устраняет эту проблему.
class D1:public B {
public:
void f;
void g;
};
D1 d1; // OK
Несмотря на то что все чисто виртуальные функции замещаются, результирующий класс остается абстрактным.
class D2:public B {
public:
void f;
// no g
};
D2 d2; // ошибка: класс D2 — (по-прежнему) абстрактный
class D3:public D2 {
public:
void g;
};
D3 d3; // OK
14.4. Преимущества объектно– ориентированного программирования
Circle
является производным от класса Shape
, или разновидностью класса Shape, то делаем это для того, чтобы достичь следующих целей (по отдельности или всех вместе). • Наследование интерфейса. Функция, ожидающая аргумент класса
Shape
(обычно в качестве аргумента, передаваемого по ссылке), может принять аргумент класса Circle
(и использовать его с помощью интерфейса класса Shape
). • Наследование реализации. Когда мы определяем класс
Circle
и его функции-члены, мы можем использовать возможности (т.е. данные и функции-члены), предоставляемые классом Shape
.
Never_do_this
, относительно которого класс Shape
является открытым базовым классом. Затем мы могли бы заместить функцию Shape::draw_lines
функцией, которая не рисует фигуру, а просто перемещает ее центр на 100 пикселей влево. Этот проект фатально неверен, поскольку, несмотря на то, что класс Never_do_this
может предоставить интерфейс класса Shape
, его реализация не поддерживает семантику (т.е. поведение), требуемое классом Shape
. Никогда так не делайте!
Shape
) без информации о реализациях (в данном случае классах, производных от класса Shape
).
Circle
), которое обеспечивается возможностями базового класса (например, класса Shape
).
Shape::draw
, которая в свою очередь вызывает виртуальную функцию draw_lines
класса Shape
, чтобы она выполнила реальную работу, связанную с выводом изображений на экран. Ни “графический движок”, ни класс Shape
не знают, какие виды фигур существуют. В частности, наш “графический движок” (библиотека FLTK и графические средства операционной системы) написан и скомпилирован за много лет до создания наших графических классов! Мы просто определяем конкретные фигуры и вызываем функцию attach
, чтобы связать их с объектами класса Window
в качестве объектов класса Shape
(функция Window::attach
получает аргумент типа Shape&
; см. раздел Г.3). Более того, поскольку класс Shape
не знает о наших графических классах, нам не нужно перекомпилировать класс Shape
каждый раз, когда мы хотим определить новый класс графического интерфейса.