Generally, you want to figure out the best way to make things modular, and break it down in that way.
So in the case of different guns, it probably depends on how different each one is, but you’d probably want to create a base class that contains shared functionality (ammo counts, reload times, etc) and make a child for each one that contains the data that’s not shared (mesh, animations, sound & FX).
You also want to think about which way information needs to flow. Typically, since the pawn & controller are high level classes, they are good managers for general information. In the case of the gun, I’d probably build something into the pawn that allows for the pawn to hold a general “weapon” blueprint type (an array of BP_Weapon for example). That way you can assign different weapons and aren’t carrying the data for everything at all times.
As far as triggering, I’d probably use an interface… like each gun implements something like BPI_GunCommunication and on input event “fire weapon” you call the interface on a reference to whatever gun is equipped, and a “stop firing” on release of the “fire weapon” event.
I’m not working on anything that uses that sort of system personally, but I think generally you want to figure out how much functionality you can make modular, and cascade down through the children. Also, architecturally, you should think about what needs to communicate with what. The controller needs to tell the pawn to fire which needs to tell the gun to fire, but does the gun need to tell the pawn anything? Probably not, so it makes sense as a child.