Полиморфизм

Глава 4. Объектно-ориентированное программирование в C++ #

4.3 Полиморфизм в C++ #

Полиморфизм является одним из фундаментальных принципов объектно-ориентированного программирования, позволяющим создавать гибкие и расширяемые иерархии классов.

1. Виртуальные функции #

1.1 Основные понятия #

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

1.2 Синтаксис #

class BaseClass {
public:
    virtual void someMethod() {
        // Базовая реализация
    }
};

class DerivedClass : public BaseClass {
public:
    // Переопределение виртуальной функции
    void someMethod() override {
        // Новая реализация
    }
};

1.3 Ключевые особенности #

  • Ключевое слово virtual в базовом классе
  • Ключевое слово override в производном классе (необязательно, но рекомендуется)
  • Позволяет динамически определять метод во время выполнения

1.4 Пример использования #

class Shape {
public:
    virtual double calculateArea() {
        return 0.0;
    }
};

class Circle : public Shape {
private:
    double radius;
public:
    Circle(double r) : radius(r) {}
    
    double calculateArea() override {
        return 3.14159 * radius * radius;
    }
};

class Rectangle : public Shape {
private:
    double width, height;
public:
    Rectangle(double w, double h) : width(w), height(h) {}
    
    double calculateArea() override {
        return width * height;
    }
};

int main() {
    Shape* shapes[2];
    shapes[0] = new Circle(5);
    shapes[1] = new Rectangle(4, 6);

    for (auto shape : shapes) {
        // Полиморфный вызов метода
        std::cout << "Area: " << shape->calculateArea() << std::endl;
    }
    
    return 0;
}

1.5 Важные замечания #

  • Виртуальные функции создают дополнительные накладные расходы
  • Используют механизм таблиц виртуальных функций (vtable)
  • Деструкторы базовых классов должны быть виртуальными при наследовании

2. Абстрактные классы #

2.1 Определение #

Абстрактный класс — класс, который содержит хотя бы один чисто виртуальный метод и не может быть instantiated (создан как объект).

2.2 Синтаксис #

class AbstractBase {
public:
    // Чисто виртуальная функция
    virtual void pureVirtualMethod() = 0;
};

2.3 Характеристики #

  • Содержит хотя бы один чисто виртуальный метод (= 0)
  • Нельзя создать объект абстрактного класса
  • Может содержать обычные методы и поля
  • Производные классы обязаны реализовать все чисто виртуальные методы

2.4 Пример #

class Animal {
public:
    // Чисто виртуальный метод
    virtual void makeSound() = 0;
    
    // Обычный метод
    void breathe() {
        std::cout << "Дыхание" << std::endl;
    }
};

class Dog : public Animal {
public:
    // Реализация чисто виртуального метода
    void makeSound() override {
        std::cout << "Гав!" << std::endl;
    }
};

class Cat : public Animal {
public:
    void makeSound() override {
        std::cout << "Мяу!" << std::endl;
    }
};

3. Интерфейсы #

3.1 Концепция интерфейсов в C++ #

В C++ нет прямого ключевого слова для интерфейсов, как в Java. Интерфейс реализуется через абстрактный класс, содержащий только чисто виртуальные методы.

3.2 Реализация интерфейса #

class ILogger {
public:
    virtual void log(const std::string& message) = 0;
    virtual void error(const std::string& message) = 0;
    virtual ~ILogger() {} // Виртуальный деструктор
};

class ConsoleLogger : public ILogger {
public:
    void log(const std::string& message) override {
        std::cout << "Log: " << message << std::endl;
    }
    
    void error(const std::string& message) override {
        std::cerr << "Error: " << message << std::endl;
    }
};

3.3 Множественная реализация интерфейсов #

class ISerializable {
public:
    virtual std::string serialize() = 0;
    virtual void deserialize(const std::string& data) = 0;
    virtual ~ISerializable() {}
};

class User : public ILogger, public ISerializable {
public:
    // Реализация методов ILogger
    void log(const std::string& message) override { /* ... */ }
    void error(const std::string& message) override { /* ... */ }
    
    // Реализация методов ISerializable
    std::string serialize() override { /* ... */ }
    void deserialize(const std::string& data) override { /* ... */ }
};

Заключение #

Полиморфизм в C++ предоставляет мощные возможности для создания гибких и расширяемых иерархий классов:

  • Виртуальные функции позволяют динамически вызывать методы
  • Абстрактные классы создают контракты для наследников
  • Имитация интерфейсов через абстрактные классы обеспечивает четкое разделение поведения

Рекомендации #

  • Используйте виртуальные функции осознанно
  • Всегда объявляйте виртуальный деструктор в базовых классах
  • Применяйте override для явного переопределения методов
  • Помните о производительности при частом использовании полиморфизма

Типичные ошибки #

  1. Забывать о виртуальном деструкторе
  2. Неправильно использовать override
  3. Создавать объекты абстрактных классов
  4. Чрезмерное усложнение иерархии классов