We create three functions inside the Selectable interface. IsSelectable returns a Boolean to indicate whether the object is selectable. You could avoid this and simply use TrySelect, given that it returns a Boolean value to indicate success, but, for example, you might want to know if the object inside your UI is a valid selection without having to actually try it.
TrySelect actually attempts to select the object. There's no explicit contract forcing users to respect IsSelectable when trying to select the object, so TrySelect is named to communicates that the selection may not always succeed.
Lastly, Deselect is a function that's added to allow objects to handle losing the player selection. This could involve changing the UI elements, halting sounds or other visual effects, or simply removing a selection outline from around the unit.
The default implementations of the functions return true for IsSelectable (the default is for any object to be selectable), true for TrySelect (selection attempts always succeed), and issue a debug assert if Deselect is called without being implemented by the class.
You could also implement Deselect as a pure virtual function if you wish. SelectableCube is a new class inheriting from PhysicsCube, but also implementing the ISelectable interface. It also overrides NotifyHit, a virtual function defined in AActor that triggers when the actor undergoes a RigidBody collision.
We call the constructor from PhysicsCube with the Super() constructor call inside the implementation of SelectableCube. We then add our own implementation, which calls SetNotifyRigidBodyCollision(true) on our static mesh instance. This is necessary, because by default, RigidBodies (such as PrimitiveComponents with a collision) don't trigger Hit events as a performance optimization. As a result, our overridden NotifyHit function would never be called.
Within the implementation of NotifyHit, we call some of the ISelectable interface functions on ourselves. Given that we know we are an object that inherits from ISelectable, we don't need to cast to an ISelectable* to call them.
We check to see if the object is selectable with IsSelectable and, if so, we try to actually perform the selection using TrySelect. NonSelectableCube inherits from SelectableCube, so we can force the object to never be selectable.
We accomplish this by overriding the ISelectable interface functions again. Within ANonSelectableCube::IsSelectable(), we print a message to the screen so that we can verify that the function is being called, and then return false to indicate that the object isn't selectable at all.
In case the user doesn't respect IsSelectable(), ANonSelectableCube::TrySelect() always returns false to indicate that the selection wasn't successful.
Given that it is impossible for NonSelectableCube to be selected, Deselect() calls unimplemented(), which throws an assert warning that the function was not implemented.
Now, when playing your scene, each time SelectableCube/NonSelectableCube hits another object, causing a RigidBody collision, the actor in question will attempt to select itself, and print messages to the screen.