Абстрактный класс в объектно-ориентированном программировании — базовый класс, который не предполагает создания экземпляров. Абстрактные классы реализуют на практике один из принципов ООП — полиморфизм. Абстрактный класс может содержать (и не содержать[1]) абстрактные методы и свойства. Абстрактный метод не реализуется для класса, в котором описан, однако должен быть реализован для его неабстрактных потомков. Абстрактные классы представляют собой наиболее общие абстракции, то есть имеющие наибольший объём и наименьшее содержание.

В одних языках создавать экземпляры абстрактных классов запрещено, в других это допускается (например, Delphi), но обращение к абстрактному методу объекта этого класса в процессе выполнения программы приведёт к ошибке. Во многих языках допустимо объявить любой класс абстрактным, даже если в нём нет абстрактных методов (например, Java), именно для запрета создания экземпляров. Абстрактный класс можно рассматривать в качестве интерфейса к семейству классов, порождённому им, но, в отличие от классического интерфейса, абстрактный класс может иметь определённые методы, а также свойства.

Абстрактные методы всегда являются виртуальными, однако «абстрактный» и «виртуальный» - разные понятия.

Примеры

править

В Delphi может быть объявлен абстрактный класс с абстрактными методами:

TAbstractClass = class 
  procedure NonAbstractProcedure;
  procedure AbstractProcedure; abstract;
end;

Для такого класса может быть создан объект, но обращение к методу AbstractProcedure этого объекта во время выполнения вызовет ошибку.

В последних версиях Delphi также может быть объявлен абстрактным сам класс:

TAbstractClass = class abstract
  procedure SomeProcedure;
end;

Хотя метод SomeProcedure может быть не абстрактным и реализован в рамках этого класса, создавать объекты объявленного таким образом класса недопустимо.

На C++ абстрактный класс объявляется включением хотя бы одной чистой виртуальной функции, типа virtual _сигнатура_функции_ =0;, которая, как и другие, может быть заменена. Пример на языке программирования C++:

#include <iostream>

class CA { // Абстрактный класс
  public:
    CA ( void ) { std::cout << "This object of the class "; }

    virtual void Abstr ( void ) = 0; // Чистая (пустая) виртуальная функция.
    void         fun   ( void ) { std::cout << "Реализация не будет наследоваться!"; }

    ~CA () { std::cout << "." << std::endl; } //Вызывается в обр. порядке конструкторов
  };

class CB : public CA {
  public:
    CB ( void ) { std::cout << "CB;"; }

    void Abstr ( void ){ std::cout << " call function cb.Abstr();"; } //Подменяющая функция.
    void fun   ( void ){ std::cout << " call function cb.fun()"; }

    ~CB () {} // Неверно для абстр. кл. ~CB(){ ~CA(); } 
  };

class CC : public CA {
  public:
    CC ( void ) { std::cout << "CC;"; }

    void Abstr ( void) { std::cout << " call function cc.Abstr();"; } //Подменяющая функция.
    void fun   ( void ) { std::cout << " call function cc.fun()"; }

  ~CC () {} // Неверно для абстр. кл. ~CC(){ ~CA(); } 
  };

int main () {
  std::cout << "Program:" << std::endl;
  CB cb;
  cb.Abstr(); cb.fun(); cb.~CB();

  CC cc;
  cc.Abstr(); cc.fun(); cc.~CC();

  return 0;
  }

Результат работы программы:

Program:
This object of the class CB; call function cb.Abstr(); call function cb.fun().
This object of the class CC; call function cc.Abstr(); call function cc.fun().
.
.

Модификатор abstract указывает на то, что класс может быть использован только как базовый класс при наследовании. Абстрактные классы могут содержать абстрактные методы и методы доступа. Создавать экземпляры абстрактного класса нельзя через вызов конструктора, но экземпляр абстрактного класса создаётся неявно при построении экземпляра производного конкретного класса. Неабстрактный класс, являющийся производным от абстрактного, должен содержать фактические реализации всех наследуемых абстрактных методов и методов доступа. Чтобы указать отсутствие реализации в методе или свойстве, воспользуйтесь модификатором abstract в объявлении метода или свойства. Абстрактный метод - это неявный виртуальный метод. Объявления абстрактных членов (методов, свойств, событий) допускаются только в абстрактных классах и интерфейсах (стереотипах, являющихся аналогом чистых абстрактных классов, в которых запрещена любая реализация). Поскольку объявление абстрактного метода не предоставляет фактической реализации, тело метода отсутствует, объявление метода просто заканчивается точкой с запятой, аналогично объявлению прототипов:

public abstract void AbstractMethod();

Реализация предоставляется методом переопределения override, который является членом неабстрактного класса.

Использование статических или виртуальных модификаторов в объявлении абстрактного метода или свойства является недопустимым. Действие абстрактных свойств аналогично абстрактным методам, за исключением отличий в синтаксисе объявлений и вызовов. Абстрактное унаследованное свойство может быть переопределено в производном классе за счёт включения объявления свойства, использующего модификатор переопределения.

    abstract class BaseClass   // Abstract class
    {
        protected int _x = 100;
        protected int _y = 150;
        public abstract void AbstractMethod();   // Abstract method
        public abstract int X    { get; }
        public abstract int Y    { get; }
    }

    class DerivedClass : BaseClass
    {
        public override void AbstractMethod()
        {
            _x++;
            _y++;
        }

        public override int X   // overriding property
        {
            get
            {
                return _x + 10;
            }
        }

        public override int Y   // overriding property
        {
            get
            {
                return _y + 10;
            }
        }

        static void Main()
        {
            DerivedClass o = new DerivedClass();
            o.AbstractMethod();
            Console.WriteLine("x = {0}, y = {1}", o.X, o.Y);
        }
    }
    // Output: x = 111, y = 161

Абстрактный класс должен предоставлять реализацию для всех членов интерфейса. Абстрактный класс, реализующий интерфейс, может отображать методы интерфейса в абстрактных методах.

interface I
{
    void M();
}
abstract class C : I
{
    public abstract void M();
}

Абстрактный класс с модификатором sealed использовать нельзя, поскольку модификатор abstract и sealed имеют взаимоисключающие значения. Модификатор sealed запрещает наследовать класс, в то время как модификатор abstract указывает, что класс обязан иметь производные классы.

Примечания

править
  1. Abstract Methods and Classes (The Java™ Tutorials > Learning the Java Language > Interfaces and Inheritance). Дата обращения: 30 сентября 2010. Архивировано 2 августа 2010 года.

См. также

править

Литература

править
  • Подбельский В. В. Глава 10.3 Виртуальные функции и абстрактные классы \\ Абстрактные классы. // Язык Си++ / рец. Дадаев Ю. Г.. — 4. — М.: Финансы и статистика, 2003. — С. 365-373. — 560 с. — ISBN 5-279-02204-7, УДК 004.438Си(075.8) ББК 32.973.26-018 1я173.