Difference between event and delegate

Who can explain me what the difference between DECLARE_EVENT and DECLARE_DYNAMIC_MULTICAST_DELEGATE, I didn’t catch. What is the profit of declare friend class in event scope, if I still can call Broadcast method from any place of code?

DOCS: While any class can bind events, only the class that declares the event may invoke the event’s Broadcast, IsBound, and Clear functions. This means event objects can be exposed in a public interface without worrying about giving external classes access to these sensitive functions.
https://docs.unrealengine.com/en-US/…nts/index.html



#define FUNC_DECLARE_EVENT( OwningType, EventName, ... ) \
class EventName : public TBaseMulticastDelegate<__VA_ARGS__> \
{ \
friend class OwningType; \
};


1 Like

I’ve found the same question. **zeryzhang, **in his last comment, point out, it’s incomplete design for key functions encapsulation.

Actual link is Delegate events does't work?

I noticed the difference between Event and Delegate: Event only allows the owning class to perform operations like Broadcast and Clear, while Delegate has no such restrictions. This naturally led me to think of a use case for Event: when declared as public, it should allow external classes to add functions while preventing them from calling Broadcast. For example:

UCLASS()
class UInnerClass : public UObject
{
	GENERATED_BODY()
public:
	DECLARE_EVENT(UInnerClass, FInnerEvent)
	FInnerEvent InnerEvent;
private:
    // A private function, for internal use only.
	void Func()
	{
		InnerEvent.Broadcast();// It's OK
	}
};

UCLASS()
class UOuterClass : public UObject
{
	GENERATED_BODY()
private:
	UPROPERTY()
	UInnerClass* InnerClassInstance;
	void Callback() {}
	void Func()
	{
		InnerClassInstance->InnerEvent.AddUObject(this, &UOuterClass::Callback); // It's OK, event allowed to bind from outside
		InnerClassInstance->InnerEvent.Broadcast(); // Error here, event not allowed to broadcast from outside
	}
};

However, when I tried to implement this idea in my code, it didn’t work as expected—external classes could still call Broadcast. So, I looked into the source code of Event and Delegate and found the following differences:

DECLARE_EVENT(UInnerClass, FInnerEvent)
class FInnerEvent : public TMulticastDelegate<void()>
{
	friend class UInnerClass;
};

DECLARE_MULTICAST_DELEGATE(FInnerDelegate)
typedef TMulticastDelegate<void()> FInnerDelegate;

Clearly, both are instantiated from TMulticastDelegate. The only distinction is that Event is separately derived and sets its inner class as a friend. But to satisfy Delegate’s requirement of allowing external calls to Broadcast, the Broadcast function is declared as public.

template <typename... ParamTypes, typename UserPolicy>
class TMulticastDelegate<void(ParamTypes...), UserPolicy> : public TMulticastDelegateRegistration<void(ParamTypes...), UserPolicy>
{
public:
    void Broadcast(ParamTypes... Params) const;
};

This means Event fails to block external calls as intended, rendering the friend declaration pointless. May I ask whether this is a bug or if I’ve misunderstood how Event is supposed to work?