Is there a way in a C++ UObject subclass to create a UPROPERTY(or something) member variable that has a function type and can be assigned a Blueprint function, and called from C++?
Like say I want to have a function that takes an int as input and returns an int as output.
In standard C++ I can write this like std::function<int(int)>.
If you’re trying to delegate to blueprint and it’s meant to be something provided by a blueprint derived from your native class, you should probably use Seda’s suggestion. On the other hand if you’ve got something that is meant to inform other objects, like widget events, delegates are the way to go.
There’s a lot more to delegates and what you can do with them, but this should hopefully get you started.
I agree – I think the multicast delegate is a better match for what OP requests than simply a function you must override. Delegates allow binding to whatever event/function in whatever target you want to call, without messing with subclassing the sending class.
…are. I guess the latter can be rebound at runtime whereas the former cannot? And the former must be implemented in a Blueprint subclass whereas the latter can be bound to anything?
Basically. You can think of a BlueprintImplementableEvent or BlueprintNativeEvent function as the equivalent to a virtual function and a delegate as just alternate version of std::function.
There are some restrictions to what can be bound to Dynamic Delegates (they can only be bound to UFUNCTIONs).
That is correct. A _DELEGATE_ is generally like a function pointer member, and a UFUNCTION(BlueprintImplementableEvent) is like a virtual function.
Function pointer members, or in this case, delegates, are better from the point of view of the implementing class itself, because it allows arbitrary other classes to hook in, without any further code changes.
In general, virtual functions are bad to express variation points for the declaring class – their main benefit is in expressing behavior to be used by OTHER classes, as when used by interfaces. Implementation inheritance where implementing classes have to call up to parent classes, and where you have to subclass to implement variation, was thought to be a great idea in the 90s when C++ was first made, but has turned out to frequently lead to poor structure in practice. (This is one reason that modern C++ tends to prefer templates and composition, btw.)
That doesn’t mean that you can’t build fine products using implementation inheritance and overridden virtual functions, just that you typically end up paying more doing so (human time, as well as computer time.)
This is a bigger topic, and has been subject of some C++con talks and such
In brief, implementation inheritance ends up losing for two main reasons:
You have to actually subclass to vary whatever it is you want to vary. Subclassing is fragile to any change in any of the superclasses.
Figuring out where something is defined becomes really hard, and making sure that all the child classes call Super::whatever() at the right times ends up being really hard.
Composition (for “hard coupling”) and loose binding (for “runtime coupling”) end up being more maintainable, because they physically separate the design of the “sender” from the design of the “receiver.”
If you don’t like hard-core std::bind type function binding, a pure abstract base class is a nice middle road, where the expectations are all laid out in a clear list of functions, but whoever “does the thing” (implements the PABC) is not otherwise coupled to the implementation of whover “says to do the thing” (the owner/caller of the interface.)