Чем отличается интерфейс от абстрактного класса?cplus-90

Основные концепции

В C++ (в отличие от некоторых других языков) нет формального разделения на интерфейсы и абстрактные классы на уровне языка, но есть устоявшиеся паттерны их реализации.

Абстрактный класс

Класс, содержащий хотя бы одну чисто виртуальную функцию:

class AbstractClass {
public:
    virtual void mustImplement() = 0;  // Чисто виртуальная функция
    virtual ```AbstractClass() {}       // Виртуальный деструктор
};

Интерфейс

Класс, содержащий только чисто виртуальные функции и не имеющий членов-данных:

class Interface {
public:
    virtual void method1() = 0;
    virtual void method2() = 0;
    virtual ```Interface() = default;
};

Ключевые различия

ХарактеристикаАбстрактный классИнтерфейс
Члены-данныеМожет содержатьНе содержит
Реализации методовМожет иметь реализованные методыТолько чисто виртуальные функции
СостояниеМожет хранить состояниеНе имеет состояния
НаследованиеМожет наследовать от других классовОбычно "чистый" интерфейс
Модификаторы доступаМожет иметь protected/private членыТолько public методы

Когда использовать

Абстрактный класс:

  1. Есть общая реализация для производных классов
  2. Необходимо хранить общее состояние
  3. Нужна частичная реализация функциональности
class AbstractShape {
protected:
    Color color;  // Общее состояние
public:
    virtual double area() const = 0;
    void setColor(Color c) { color = c; }  // Общая реализация
};

Интерфейс:

  1. Нужно определить только контракт
  2. Требуется множественное наследование
  3. Важна слабая связность компонентов
class Drawable {
public:
    virtual void draw() const = 0;
    virtual ```Drawable() = default;
};

class Serializable {
public:
    virtual std::string serialize() const = 0;
    virtual ```Serializable() = default;
};

Особенности C++

  1. Множественное наследование:

    class Concrete : public Interface1, public Interface2 {...};
    
  2. Техника разделения интерфейса (Interface Segregation Principle):

    class Printer {
    public:
        virtual void print() = 0;
        virtual ```Printer() = default;
    };
    
    class Scanner {
    public:
        virtual void scan() = 0;
        virtual ```Scanner() = default;
    };
    
  3. Отличие от других языков:

    • В C++ нет ключевого слова interface
    • В C++20 появились Concepts, которые можно рассматривать как альтернативу интерфейсам

Рекомендации по проектированию

  1. Для интерфейсов:

    • Используйте только чисто виртуальные методы
    • Объявляйте виртуальный деструктор
    • Избегайте членов-данных
  2. Для абстрактных классов:

    • Помечайте нереализуемые методы как = 0
    • Предоставляйте полезную базовую реализацию
    • Защищайте общее состояние

Резюмируем

Главные различия:

  1. Интерфейс - только чисто виртуальные методы без состояния (контракт)
  2. Абстрактный класс - может содержать реализацию и состояние (частичная реализация)

В C++:

  • Интерфейс реализуется как абстрактный класс без членов-данных
  • Абстрактный класс - более общая концепция
  • Выбор зависит от потребностей проектирования (состояние, повторное использование кода, множественное наследование)