Производные классы
6.3 Абстрактные классы
Многие классы сходны с классом employee тем, что в них можно дать разумное определение виртуальным функциям. Однако, есть и другие классы. Некоторые, например, класс shape, представляют абстрактное понятие (фигура), для которого нельзя создать объекты. Класс shape приобретает смысл только как базовый класс в некотором производном классе. Причиной является то, что невозможно дать осмысленное определение виртуальных функций класса shape:
class shape { // ... public: virtual void rotate(int) { error("shape::rotate"); } virtual void draw() { error("shape::draw"): } // нельзя ни вращать, ни рисовать абстрактную фигуру // ... };
Создание объекта типа shape (абстрактной фигуры) законная, хотя совершенно бессмысленная операция:
shape s; // бессмыслица: ``фигура вообще''
Она бессмысленна потому, что любая операция с объектом s приведет к ошибке.
Лучше виртуальные функции класса shape описать как чисто виртуальные. Сделать виртуальную функцию чисто виртуальной можно, добавив инициализатор = 0:
class shape { // ... public: virtual void rotate(int) = 0; // чисто виртуальная функция virtual void draw() = 0; // чисто виртуальная функция };
Класс, в котором есть чисто виртуальные функции, называется абстрактным. Объекты такого класса создать нельзя:
shape s; // ошибка: переменная абстрактного класса shape
Абстрактный класс можно использовать только в качестве базового для другого класса:
class circle : public shape { int radius; public: void rotate(int) { } // нормально: // переопределение shape::rotate void draw(); // нормально: // переопределение shape::draw circle(point p, int r); };
Если чисто виртуальная функция не определяется в производном классе, то она и остается таковой, а значит производный класс тоже является абстрактным. При таком подходе можно реализовывать классы поэтапно:
class X { public: virtual void f() = 0; virtual void g() = 0; }; X b; // ошибка: описание объекта абстрактного класса X class Y : public X { void f(); // переопределение X::f }; Y b; // ошибка: описание объекта абстрактного класса Y class Z : public Y { void g(); // переопределение X::g }; Z c; // нормально
Абстрактные классы нужны для задания интерфейса без уточнения каких-либо конкретных деталей реализации. Например, в операционной системе детали реализации драйвера устройства можно скрыть таким абстрактным классом:
class character_device { public: virtual int open() = 0; virtual int close(const char*) = 0; virtual int read(const char*, int) =0; virtual int write(const char*, int) = 0; virtual int ioctl(int ...) = 0; // ... };
Настоящие драйверы будут определяться как производные от класса character_device.
После введения абстрактного класса у нас есть все основные средства для того, чтобы написать законченную программу.