Using classes without defining

Hi,
I guess it is a simple question but I couldnt get it work somehow.
I have a controller script called Main. The Main should call a function when the mouse button is down. But Main is calling spells. So I am creating 4 different seperate classes called Fireball, Lightning, Freeze and Rock. Those 4 classes has the same variables and same funtion name but they functions are working differently. My plan is to add Main and one of the Spell classes to my gameobject and from Main, I want to access to the attached class.
The dirty way to do it is this:

    public class Main : MonoBehaviour
    {
        public Fireball curspell;
        public Lightning curspell2;
        public Freeze curspell3;
        public Rock curspell4;
        int selectedSpell = 1;

        void Start ()
        {
            if (selectedSpell == 1)
                curspell = Camera.main.GetComponent<FireBall>();
            if (selectedSpell == 2)
                curspell2 = Camera.main.GetComponent<Lightning>();
            if (selectedSpell == 3)
                curspell3 = Camera.main.GetComponent<Freeze>();
            if (selectedSpell == 4)
                curspell4 = Camera.main.GetComponent<Rock>();
        }

        void Update()
        {
            if (selectedSpell == 1)
                curspell.fire();
            if (selectedSpell == 2)
                curspell2.fire();
            if (selectedSpell == 3)
                curspell3.fire();
            if (selectedSpell == 4)
                curspell4.fire();
        }
        
    }

But of course it is a very dirty way. I want to use the curspell as a generic type of class so I can do something like that:

public class Main : MonoBehaviour
{
public xxxGenericxxx curspell;
int selectedSpell = 1;

    void Start ()
    {
        if (selectedSpell == 1)
            curspell = Camera.main.GetComponent<FireBall>();
        if (selectedSpell == 2)
            curspell = Camera.main.GetComponent<Lightning>();
        if (selectedSpell == 3)
            curspell = Camera.main.GetComponent<Freeze>();
        if (selectedSpell == 4)
            curspell = Camera.main.GetComponent<Rock>();
    }

    void Update()
    {

            curspell.fire();

    }

}

The inheritance or polymorphism didn’t work for me or I do not know how to use it in this way but I am sure there is a way to do it. Do anyone has any idea?
Thanks

Inheritance is indeed what you want. This covers the very basics of inheritance and polymorphism. You will need a base class, let’s call it Spell.

public abstract class Spell : MonoBehaviour {
    public abstract void Cast();
}

Abstract means it can’t be attached to objects. But you can attach a non-abstract subclass. Then all of your spells will inherit from that.

public class FireBall : Spell {
    public override void Cast() {
        // Do Stuff
    }
}

Then your Main can use a Spell.

public class Main : MonoBehaviour {
    public Spell spell;

    void Start() {
        spell = Camera.main.GetComponent<Spell>();
    }

    void Update() {
        spell.Cast();
    }
}

You will need to update the reference to spell in Main whenever the player changes the spell they want.

Interfaces technically would be better, but if you’re having trouble just stick with regular inheritance.