Инструменты пользователя

Инструменты сайта


examination:oop:question45

Абстрактные базовые классы: назначение, определение. Чисто виртуальные функции. Методическая ценность абстрактных классов

Многие классы сходны с классом 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. После введения абстрактного класса у нас есть все основные средства для того, чтобы написать законченную программу.

examination/oop/question45.txt · Последние изменения: 2014/01/15 12:22 (внешнее изменение)