The problem you have encountered is a fundamental part of the design of object oriented programming.
Classes hold in themselves properties (variables) and methods (functions, events).
You see, a child class inherits ALL of the variables and functions of the parent class. You can see the inherited variables by clicking on the “eye” icon above your varable list’s search box.
This means that if you call a method or try to get a property of the parent class from a child class it is GUARANTEED to have it. This is why child class references can be saved in parent type variables.
Yes, the child can change (override) methods or modify properties defined in the parent class but they will still have all of them and can even have additional properties and methods of their own.
On the other hand if you call a method or try to get a property specific for the child class from a parent it will not have it. This is why parent class references can NOT be saved in child type variables.
Suppose you have a child reference in a parent type variable. If you try to access the child specific variables and methods you will not be able to because you treat it as a parent. This is where downcasting (CastTo nodes) comes in. You can downcast the variable to the child type you want. The returned variable will be of that child type and you will be able to access all its methods and properties. However, casting may fail if you have saved different child reference than the one you try to cast to.
In terms of game architecture, the character usually only holds a parent class weapon.
This parent class holds all the variables like Range, Damage, Mesh, ClipSize and methods Attack(), AlternativeAttack(), Reload().
The child classes all have different values for Range, Damage and Mesh ClipSize.
They would also have different implementation (blueprint graph) on Attack(): the knife will stab, the shotgun will fire.
And would also have different implementation (blueprint graph) on AlternativeAttack(): the rifle will fire a grenade, the sniper will aim down sight.
Additionally can also have properties and methods that are unique to them: like muzzle velocity for the rifle, spread for the shotgun, zoom for the sniper, delay for the grenades.
This way your character will not care which gun is currently equipped. He/she will just call Attack() on a parent type variable and the child reference will execute whatever its specific Attack() does.
I hope I managed to explain it but be sure to read somewhere about the basics of the Object Oriented Programming (OOP). This topic is so fundamental that you will be able to find hundreds of results if you search in Google or YouTube.