Gustavo,
A grande sacada de conseguir fazer
Funcionario teste = new Gerente();
É que conseguimos fazer um código muito mais reaproveitável, pois trabalhamos de maneira mais abstrata. Podemos trabalhar com qualquer classe que herde de Funcionario. Podemos definir um método em Funcionário que todos os filhos sobrescrevem, e na prática, nos referenciaremos pelo método de Funcionário, porém será executado, em tempo de execução, o método da classe herdeira de funcionário.
Imagine que você tenha o código abaixo:
class Funcionario {
double calcSalario() {
return valorDia*22;
}
}
class Gerente extends Funcionario {
@Override
double calcSalario() {
return super.calcSalario()*1.2;
}
}
A situação é a seguinte: Gerente é um funcionário, porém com um cálculo de salário diferenciado, neste caso, ganha 20% em cima do salário base.
Agora imagina que vc tenha um array de funcionários, que poderão ser da classe Funcionario ou Gerente (ou Diretor, Presidente, etc). Se eu quisesse imprimir o salário de todos os funcionários, poderia ter o seguinte código:
class Relatorio {
public void imprimirSalarios(Funcionario[] funcionarios) {
for (Funcionario f: funcionarios) {
System.out.println(f.calcSalario());
}
}
}
Veja que devido ao Polimorfismo, quando o método calcSalario é chamado dentro do for (classe Relatorio), se a instância for de Funcionario a implementação de Funcionario será chamada, mas se a instância for de Gerente então a implementação de Gerente será chamada.
Em C++ o método calcSalario() precisaria ser virtual para termos este comportamento igual ao Java, caso contrário o método chamado iria depender do tipo da referência (Funcionario ou Gerente), por exemplo:
class Funcionario {
double calcSalario();
}
class Gerente: public Funcionario {
double calcSalario();
}
Funcionario *f = Gerente();
f->calcSalario(); // Chama a implementacao de Funcionario
Gerente *g = Gerente();
g->calcSalario(); // Chama a implementacao de Gerente
Mas se calcSalario em Gerente fosse definida como virtual, sempre seria chamado a implementação do tipo correto, por exemplo:
class Gerente: public Funcionario {
virtual double calcSalario();
}
Funcionario *f = Gerente();
f->calcSalario(); // Chama a implementação de Gerente
Espero que tenha ajudado.