Глава 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
для явного переопределения методов - Помните о производительности при частом использовании полиморфизма
Типичные ошибки #
- Забывать о виртуальном деструкторе
- Неправильно использовать
override
- Создавать объекты абстрактных классов
- Чрезмерное усложнение иерархии классов