Полиморфизм в C++ и таблицы указателей на функции в C
В этом уроке вы вызовете одну и ту же операцию для объектов разных типов: через виртуальные функции в C++ и указатели на функции в C.
Введение
Динамический полиморфизм (dynamic polymorphism) позволяет коду вызывать общую операцию, например вычисление площади, а каждому типу объекта самому решать, как её выполнить. C++ поддерживает это напрямую через виртуальные функции (virtual functions), а в C это можно имитировать указателями на функции.
Главное
- Поймите, как это делается в C, прежде чем изучать абстракции C++.
- Выражайте владение ресурсами через RAII и семантику значений (value semantics).
- Используйте типобезопасные средства C++ вместо макросов и приведений типов.
Примеры кода на C и C++
#include <stdio.h>
typedef struct Shape Shape;
struct Shape {
double value;
double (*area)(const Shape *shape);
};
double square_area(const Shape *shape) {
return shape->value * shape->value;
}
int main(void) {
Shape square = {4.0, square_area};
printf("area=%.1f\n", square.area(&square));
}
area=16.0
#include <iostream>
struct Shape {
virtual double area() const = 0;
virtual ~Shape() = default;
};
struct Square : Shape {
double side;
explicit Square(double value) : side(value) {}
double area() const override { return side * side; }
};
int main() {
Square square(4);
const Shape& shape = square;
std::cout << "area=" << shape.area() << '\n';
}
area=16
Сравнение C и C++
В C struct Shape содержит указатель на функцию area, и каждая фигура подставляет туда свою функцию вычисления площади, например square_area. В C++ виртуальные функции автоматически создают такой же механизм выбора. У базового класса также должен быть виртуальный деструктор (virtual destructor), чтобы удаление объекта через указатель на базовый класс было безопасным.
C использует соглашения об именах, обратные вызовы, макросы и struct с контекстом.
C++ предлагает абстракции с чёткими границами, безопасные по типам и обычно без дополнительных затрат при выполнении.
Упражнения для практики
Запустите обе версии, а затем измените код, чтобы увидеть разницу в безопасности, которую даёт каждый язык.
- Сначала напишите механизм на C, а затем используйте аналогичную возможность C++.
- Замените ручное освобождение ресурсов на RAII.
- Проверьте, не вызывает ли эта возможность выделение памяти или вызовы виртуальных функций.
Попрактикуйтесь на задаче
Примените материал этого урока к реальной задаче. Каждая задача запускается в браузере, с мгновенными тестами и разбором от ИИ.
Все задачи