Современный C++ и альтернативы на C

Полиморфизм в C++ и таблицы указателей на функции в C

В этом уроке вы вызовете одну и ту же операцию для объектов разных типов: через виртуальные функции в C++ и указатели на функции в C.

Введение

Динамический полиморфизм (dynamic polymorphism) позволяет коду вызывать общую операцию, например вычисление площади, а каждому типу объекта самому решать, как её выполнить. C++ поддерживает это напрямую через виртуальные функции (virtual functions), а в C это можно имитировать указателями на функции.

Главное

  • Поймите, как это делается в C, прежде чем изучать абстракции C++.
  • Выражайте владение ресурсами через RAII и семантику значений (value semantics).
  • Используйте типобезопасные средства C++ вместо макросов и приведений типов.

Примеры кода на C и C++

C
Запустить →
main.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
C++
Запустить →
main.cpp
#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

C использует соглашения об именах, обратные вызовы, макросы и struct с контекстом.

C++

C++ предлагает абстракции с чёткими границами, безопасные по типам и обычно без дополнительных затрат при выполнении.

Упражнения для практики

Запустите обе версии, а затем измените код, чтобы увидеть разницу в безопасности, которую даёт каждый язык.

  • Сначала напишите механизм на C, а затем используйте аналогичную возможность C++.
  • Замените ручное освобождение ресурсов на RAII.
  • Проверьте, не вызывает ли эта возможность выделение памяти или вызовы виртуальных функций.

Попрактикуйтесь на задаче

Примените материал этого урока к реальной задаче. Каждая задача запускается в браузере, с мгновенными тестами и разбором от ИИ.

Все задачи