Using a lambda function of type std::function<void()> or an object which is derived from an abstract class (interface) with just one virtual function isare both semantically equivalent. More general, objects and closuresclosures are semantically equivalent, that is a well known fact and true in lots of modern multi paradigm languages which support both, OOP and functional programming, not just C++. If you search a little in older questions, you find lots of variants of this question asked by people using other languages like Java, C# or Python.
The "OOP" way usually requires a little bit more boilerplate code. On the other hand, it allows to extend the base class / interface by more functions and hence to create a combined abstraction, a.k.a. "strategy pattern". In C++, full functional support (not just "pointers to function", but closures and std::function) was first introduced in C++11, if I remember correctly.
When you can do both, it is often just a matter of taste which one to prefer. I usually use the functional approach when I just need a single function to pass around, with no need to create a special abstraction aroundfor it, and refactor to virtual classes in case things get more complex and I see some benefit in having a combined interface.