It depends somewhat on the game and what the weapons do, I would say, but I’ll give you one pretty general and powerful solution.
Create a new blueprint class for your weapons. This class should have designating all the important stuff that differentiate weapons, like damage, range, damage type (if this is in your game) etc. It would probably also contain the mesh of the weapon.
If the weapon in your games differ significantly in how they work mechanically it would probably also be good to have an ability class reference for what ability this weapon should use (you would probably not need an entire different ability for each weapon, but something like a rocket launcher and a sword would be different enough that creating two abilities would be simpler than making a shared ability general enough to work for both. Also you would probably want a tag or enum for the weapon class that the unit animation blueprint can look at when attacking to know how to animate the attack.
While answering your question I’ve thought of another possibility that could also work. Have the weapons use the ability class and themselves be abilities. You would likely want to create a weapon master class that inherits from BP_Ability which contains functionality used by all or most weapons and then have weapons be child blueprints of this master class. Weapons could play an equip animation when activated and would otherwise function just like abilities. The more I think about it the more I like this solution. I don’t think I’d do something like this in a game with very simple weapon rules, such as for example Fire Emblem, but for something like Fallout or XCOM I think it would work great.
I’ll try to give you quick explanations for the UE4 features you are uncertain about:
Casting is something you do when you have a reference to an object, but the reference variable is of a more basic class than the one you want, so you cast to get access to properties that are unique to the child object. For instance, the GridUnits map in BP_GridManager contains references to all the units placed on the grid. Say that you get one of these references and want to deal damage to it. However you have a child blueprint of BP_Unit that has an armor variable which you want to subtract from the damage dealt. UnrealEngine does not know what type of unit it references when you get a reference from the GridUnits map, only that it is a unit, so you do not have access to the armor variable. To get access you need to cast, which is essentially asking Unreal Engine “is this unit a unit_armor type unit?”. If this is true you can use the access pin to get access to the armor variable. A pretty bad example, since using interfaces or simply handling the damage reduction within the unit itself would get the job done here, but I hope it helps you understand. Know that casting is a costly operation, so try to avoid using it whenever possible. Interfaces can generally do the same thing and better.