They each have advantages in different use cases.
This is probably the optimal thing to do if a) you want to guarantee that all classes have some default implementation of the function/event, and b) only children of BaseActor (or at least, few other classes) need to have the function available.
This is correct except that to be clear, the Interface only has the function *signature *(and return values), not an implementation of the function itself. This is useful if you want to be able to call the same function on classes that don’t necessarily inherit from each other.
E.g, if you want to have an “Interact” function on both a LightSwitchActor that derives from Actor and an NPC class that derives from Character, you could create an Interface with an “Interact” function, then have each of those classes implement them. At runtime, you would grab references to them as Actor objects (since they all inherit from Actor) and then call the Interface function, which will fail silently if the object doesn’t implement the interface. If you tried implementing “Interact” directly on each of the two classes, you’d have to cast them to the correct type before calling “Interact,” which can get very ugly as the number of implementing classes increases.
This isn’t really what dispatchers were designed for, imo. In this example, there’s no advantage of using a dispatcher rather than a regular event/function.
The main advantage of a dispatcher is that it enables an object X to call events on multiple objects A, B, C, … etc. without needing references to those objects or even “knowing” what those will be until runtime. For example, maybe you have many dynamically-spawned NPCs whose behavior should change when the player dies. You could either:
A. Implement an “OnDeath” event on the player BP that searches for all NPC objects and calls the “ChangeBehavior” event on each of them; or
B. Implement an “OnDeath” event dispatcher and have each NPC object bind its own “ChangeBehavior” event to it when it’s spawned
With A, the player object needs to get a reference to every NPC in the level. With B (the event dispatcher), the player object doesn’t need a reference to any of the NPCs, but the NPCs need a reference to the player object (which they probably have anyway for other functionality, or they can get easily using GetPlayerCharacter()). B resembles an Observer Pattern, which seems to be what event dispatchers were designed for.