Found my answer in Grand unified C++/blueprint cast interface explanation - UI - Epic Developer Community Forums
The solution is basically message
passing. UE4 uses the
GENERATED_IINTERFACE_BODY() macro
which you call in the IFooInterface
definition to add the Execute_*
methods as static methods of your
class. What Execute_DoSomething does
is basically send a message to a
UObject and says “Please see if you
claim to implement the methods in
IFooInterface and if so call the
DoSomething method.” This is kind of
like how classes work in languages
like python or Objective C or
Smalltalk but not how classes
generally work in C++ (which is why I
found everything so confusing).