TGViewer
Грокаем C++ Грокаем C++ @grokaemcpp · 9.37K subscribers
Post #790 4.62K
Динамический полиморфизм. ООP-style
#новичкам

Полиморфизм - это способность кода единообразно обрабатывать разные сущности. И хоть термин "полиморфизм" называют принципом ООП, это понятие в широком смысле выходит за границы этой парадигмы. Любая конструкция языка, которая позволяет единообразно управлять разными сущностями проявляет полиморфные свойства. В этом и следующих постах постараемся по верхам раскрыть сущности, реализующие полиморфизм в С++ в широком смысле.

Но раз уж заговорили об ООП, давайте для начала поговорим про полиморфизм в рамках ООП.

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

Для работы работы динамического полиморфизма нужен: базовый класс, пара наследников и виртуальные методы:

struct ITask {
virtual void Execute() = 0;
virtual ~ITask() = default;
};

struct FileDeleteTask : public ITask {
std::string path_;

FileDeleteTask(const std::string &path) : path_(path) {}

void Execute() override {
std::filesystem::remove(path_);
std::cout << "Deleted: " << path_ << std::endl;
}
};

struct S3FileUploadTask : public ITask {
std::string bucket_;
std::string path_;
std::shared_ptr<S3Client> client_;

S3FileUploadTask(const std::string &bucket, const std::string &path, const std::shared_ptr<S3Client> &client)
: bucket_{bucket}, path_{path}, client_{client} {}

void Execute() override {
client_->Upload(bucket_, path_);
std::cout << "Uploaded: " << bucket_ << ", pathL " << path_ << std::endl;
}
};


У нас есть интерфейс ITask и виртуальный метод Execute. Два других класса наследуются от ITask и переопределяют метод Execute. В задаче FileDeleteTask удаляется файл по заданному пути из файловой системы. В задаче S3FileUploadTask файл загружается в удаленное хранилище S3.

Заметим, у этих задач общий интерфейс(их можно выполнить), но они совершают разные действия.

Теперь мы можем использовать эти задачи:

void Producer1(const std::string &bucket, const std::vector<std::string> &paths,
const std::shared_ptr<S3Client> &client, std::deque<std::unique_ptr<ITask>> &tasks) {
for (const auto &path : paths)
tasks.emplace_back(std::make_unique<S3FileUploadTask>(bucket, path, client));
}

void Producer2(const std::vector<std::string> &paths, std::deque<std::unique_ptr<ITask>> &tasks) {
for (const auto &path : paths)
tasks.emplace_back(std::make_unique<FileDeleteTask>(path));
}

void Worker(std::deque<std::unique_ptr<ITask>> &tasks) {
while (!tasks.empty()) {
auto task = std::move(tasks.front());
task.pop_front();
task->Execute();
}
}


У нас есть 2 продюсера, которые кладут задачи в очередь, и воркер, который выполнятся задачи из очереди.

В очереди хранятся уникальные указатели на базовый класс ITask. Это значит, что она может хранить объекты любых наследников интерфейса ITask.

Теперь самое важное: воркеру не нужно знать, какую конкретно задачу он сейчас достанет из очереди и какой конкретно продюсер ее туда положил. Единственное, что важно - общий интерфейс. Он позволяет единообразно выполнить задачи разных типов, даже не зная их исходный тип.

В этом и суть: абстрагироваться от конкретной реализации и верхнеуровнево определить, как себя должен вести объект.

Но динамический полиморфизм не ограничивается полиморфизмом подтипов. Для него вообще иерархия классов не нужна. И в следующих постах посмотрим, что еще в С++ позволяет реализовать полиморфное поведение.

Extract common traits. Stay cool.

#OOP #cppcore
  • ❤ 29
  • 👍 10
  • 🔥 9
  • ⚡ 1
More from @grokaemcpp
  1. Oct 8, 2026​​Strict weak ordering #опытным На первый взгляд, всё выглядит рабочим: мы создаём 40 зака…
  2. Oct 7, 2026​​Где-то баг... #опытным Вот вам код: struct Order { int price; int id; }; int main() { st…
  3. Oct 5, 2026Откуда spurious wakeup на кондваре? #опытным У кондваров есть метод std::condition_variabl…
  4. Oct 1, 2026​​Stacktrace. Tips #опытным Чтобы полноценно работать со стандартными трейсами, нужно знат…
  5. Sep 28, 2026​​Stacktrace #опытным Одна из проблема исключений - непонятно, откуда оно прилетело. Ну да…
  6. Sep 25, 2026​​std::spanstream #опытным Радостная весть для всех, кто пользуется iostreams! В C++23 доб…
Threads Profile ViewerView any public Threads profile without an account.Open ThreadLook →Writing with AI? Make it sound human.Metric37 rewrites AI drafts so they read naturally. Free AI detector, 1,500 words free.Try Metric37 →