Oie Vitor, tudo bem contigo?
O que acontece é mais ou menos o seguinte:
Ao fazermos:
Gerente g = new Gerente():
Por conta de "Gerente" herdar a classe "Funcionario", automaticamente ela tem todos os métodos e atributos que "Funcionario" possui, mas além disso "Gerente" pode ter seus prórprios métodos e atributos. Por isso ao fazermos o exemplo acima, poderemos chamar tudo que "Funcionario" tem + tudo aquilo de novo que foi criado só na classe "Gerente".
Agora quando fazemos dessa maneira aqui:
Funcionario f = new Gerente():
A partir da instancia acima nós só conseguiremos acessar os métodos que a classe "Funcionario" possui, os atributos e métodos que foram criados em "Gerente" ficaram inacessíveis.
Se formos parar para pensar agora, realmente fica díficil observar qualquer situação aonde a segunda opção será usada mas isso poderia acontecer caso nós só quisessemos manipular os atributos e métodos que apenas a classe "Funcionario" tem, e ai por conta de se querer evitar possíveis erros que podem acontecer quando se trabalhamos em uma equipe, usando a referência como "Funcionario" podemos impedir que o método "autentica" seja chamado em um lugar incorreto por exemplo. Ou pode ser apenas uma escolha de preferência do programador usar a segunda opção em momentos em que não sejam necessários chamar nenhum método específico da classe "Gerente", enfim, é bom saber que essa opção existe e como ela funciona.
Espero ter conseguido solucionar sua dúvida, qualquer outro problema ou questão é só mandar por aqui :)
Bons estudos!