Atenção! Deixar claro que é conveniente seguir sempre as seguintes convenções:
protected:.
Começar por escrever no quadro as classes  Empregado e  Chefe da
Aula 7:
Explicar de novo conceito de herança. Introduzir:
class Empregado {public:Empregado(string const& nome, Sexo const sexo);
string const& nome() const;Sexo sexo() const;void mostra() const;
private:string nome_;Sexo sexo_;};
inline Empregado::Empregado(string const& nome, Sexo const sexo): nome_(nome), sexo_(sexo)
{}
inline string const& Empregado:: nome() const
{return nome_;}
inline Sexo Empregado:: sexo() const
{return sexo_;}
inline void Empregado:: mostra() const
{cout << "Nome: " << nome() << endl<< "Sexo: " << sexo() << endl;}
class Chefe : public Empregado {public:Chefe(string const& nome, string const& morada, Sexo const sexo,
int const nível);
int nível() const;void mostra() const;
private:int nível_;};
inline Chefe::Chefe(string const& nome, string const& morada, Sexo const sexo,
int const nível)
: Empregado(nome, sexo), nível_(nível)
{
}
inline int Chefe::nível() const
{return nível_;}
inline void Chefe::mostra() const
{Empregado::mostra();cout << "Nível: " << nível() << endl;}
O problema é que aparece tudo como empregados!
list<Empregado*> pessoal;
pessoal.push_back(new Empregado("João Maria", masculino));pessoal.push_back(new Chefe("Ana Maria", feminino, 4));...
for(list<Empregado*>::iterator i = pessoal.begin();
i != pessoal.end();++i)(*i)->mostra();...
for(list<Empregado*>::iterator i = pessoal.begin();
i != pessoal.end(); ++i)delete *i;
Mostrar resultado:
Nome: João Maria
Sexo: masculino
Nome: Ana Maria
Sexo: feminino
É que o método invocado depende do tipo do ponteiro e não do tipo do objecto apontado...
Fazer boneco mostrando a lista e os tipos envolvidos.

O que nós gostávamos era que fosse o tipo dos objectos
apontados a determinar o método a executar...  Precisamos de
polimorfismo: que os empregados possam assumir diversas formas e,
portanto, diferentes comportamentos.  Ou seja, precisamos que invocações de
operações através de ponteiros
para  Empregado levem a executar o respectivo método da classe
do objecto apontado!
Para isso temos de dizer ao C++ que a operação mostra() é
polimórfica ou virtual!
Se uma operação numa classe base for polimórfica, então as classes derivadas podem-na redefinir, como já acontecia. Mas o que ocorre deixa de ser uma simples ocultação: passa a ser uma sobreposição! Para que seja uma sobreposição a assinatura da operação tem de ser rigorosamente igual!
class Empregado {public:Empregado(string const& nome, Sexo const sexo);
string const& nome() const;Sexo sexo() const;virtual void mostra() const;
private:string nome_;Sexo sexo_;};
No fundo, uma sobreposição corresponde ao fornecimento de um método especializado para a classe derivada que implementa a operação da classe base.
Chama-se sobreposição porque o método a executar passa a ser seleccionado dependendo do tipo do objecto e não do tipo do ponteiro ou referência. Ou seja, o método da classe derivada sobrepõe-se ao da classe base mesmo quando invocado através de um ponteiro para a classe base: quem manda é o tipo do objecto apontado.
No caso acima o método mostra() da classe  Chefe sobrepõe-se ao
método mostra() da
classe  Empregado se o objecto apontado for um Chefe.  Por isso o nosso
código passou a funcionar!
Fazer traçado!
list<Empregado*> pessoal;
pessoal.push_back(new Empregado("João Maria", masculino));pessoal.push_back(new Chefe("Ana Maria", feminino, 4));...
for(list<Empregado*>::iterator i = pessoal.begin();
i != pessoal.end(); ++i)(*i)->mostra();...
for(list<Empregado*>::iterator i = pessoal.begin();
i != pessoal.end(); ++i)delete *i;
Se numa classe existir pelo menos uma operação polimórfica ou virtual, então a classe diz-se polimórfica. Se uma classe derivada declarar uma operação com a mesma assinatura que uma operação polimórfica da classe base, porque tenciona sobrepor o respectivo método, então essa operação será também polimórfica . Mas é boa ideia deixar esse facto bem explícito:
class Chefe : public Empregado {public:Chefe(string const& nome, string const& morada, Sexo const sexo,
int const nível);
int nível() const;virtual void mostra() const;
private:int nível_;}
De outra forma o leitor do código só sabe se uma operação é polimórfica olhando para as classes base, tendo eventualmente que subir uns quantos níveis na hierarquia de classes para o esclarecer...
A distinção que temos vindo a fazer entre operação e método só é verdadeiramente útil no contexto do polimorfismo.
Uma operação é algo
que se pode invocar para uma instância de uma classe, eventualmente através de
um ponteiro ou de uma referência, para atingir determinado objectivo. 
Assim, na classe Empregado existe uma operação mostra()
que é suposto mostrar informação completa sobre um empregado no ecrã.
Um método é a implementação de um método para uma classe concreta. Assim, quando se invoca uma operação, é um método que é executado.
A distinção, claro está, é particularmente relevante quando há polimorfismo. Quando não há polimorfismo, a cada operação corresponde um método, que é a sua única implementação.
Rever exemplo das listas e dizer que no ciclo se invoca a operação, que leva à execução de diferentes métodos.
A questão portanto está em saber como é feita a ligação entre a operação invocada e o método de facto executado.
Quando uma operação não é polimórfica, é o compilador que decide qual o método que é executado quando se invoca a operação: nesse caso diz-se que houve ligação estática. O compilador decide o método que é executado com base no tipo da variável através do qual essa operação é invocada, mesmo que seja um ponteiro ou uma referência. Ou seja, a distinção entre operação e método é pouco relevante.
Quando uma operação é polimórfica, só durante a execução do programa se sabe ao certo que método é executado quando se invoca a operação, pois depende da classe do objecto e não da classe do ponteiro ou referência para ele: chama-se ligação dinâmica! O compilador não pode adivinhar o tipo do objecto apontado. Só durante a execução do programa essa questão poderá ser esclarecida. (Na prática a ligação continua a ser estática se a invocação se fizer através de uma variável simples e não de um ponteiro ou referência.) Neste caso a distinção entre operação e método é fundamental, pois podem existir vários métodos que implementam a mesma operação.
Uma classe derivada não é obrigada a sobrepor versões especializadas dos métodos da classe base! I.e., uma classe não é obrigada a fornecer implementações especializadas de uma operação polimórfica de uma classe base. Só se achar que tal é necessário.
Há duas razões para que algumas operações de classes polimórficas não sejam polimórficas:
O polimorfismo tem um pequeno problema ainda.  Suponham que a classe 
Chefe tem dentro uma lista de subordinados:
Discutir um pouco que a hierarquia de classes é conceptual e nada tem a ver com relações de poder, que estão representadas através da lista de subordinados.
class Chefe : public Empregado {public:Chefe(string const& nome, string const& morada, Sexo const sexo,
int const nível);
int nível() const;virtual void mostra() const;
void subordina(Empregado* const subordinado);
private:int nível_;list<Empregado*> subordinados;
}
inline void Chefe:: subordina(Empregado*constsubordinado)
{subordinados.push_back(subordinado);}
Que acontece no seguinte código?
Acontece que ao se destruir o chefe, o C++ chama o destrutor dolist<Empregado*> pessoal;Empregado* pe = new Empregado("João Maria", masculino);pessoal.push_back(pe);
Chefe* pc = new Chefe("Ana Maria", feminino, 4);pc->subordina(pe);pessoal.push_back(pc);
for(list<Empregado*>::iterator i = pessoal.begin(); i != pessoal.end(); ++i)(*i)->mostra();...
for(list<Empregado*>::iterator i = pessoal.begin();
i != pessoal.end(); ++i)delete *i;
Empregado! 
Por isso a lista de subordinados nunca é destruída! 
Os elos da cadeia duplamente ligada ficam a ocupar memória!  
Com resolver o problema? Temos de tornar o destrutor polimórfico ou virtual na classe base mesmo que não faça nada!
class Empregado {public:Empregado(string const& nome, Sexo const sexo);
virtual ~Empregado() {}
string const& nome() const;Sexo sexo() const;virtual void mostra() const;
private:string nome_;Sexo sexo_;};
Regra:
Se uma classe é base de uma hierarquia de classes polimórficas, tem de definir um destrutor virtual!
Ok. Até agora vimos operações polimórficas ou virtuais e vimos que conduziam ao polimorfismo e à ligação dinâmica. Falta-nos outro assunto importante.
Suponham os seguintes conceitos relacionados:
class Veículo {...};
class Automóvel : public Veículo {...};
class Motociclo: public Veículo {...};
class HondaNX650 : public Motociclo {...};
class AudiTT : public Automóvel {...};

Quais destes conceitos são concretos e quais são abstractos?
Existem instâncias de  HondaNX650 por aí?  E de
 AudiTT?  Sim!  São classe concretas!
Existem instâncias de  Motociclo por aí?  Não! 
Existem instâncias de HondaNX650, de  YamahaDiversion, etc., mas
não simplesmente de Motociclo,  Automóvel ou
 Veículo! 
São conceitos abstractos!
Suponham que pretendíamos fazer um editor de figuras bidimensionais.
Começamos por definir algumas classes úteis:
Discutir. O melhor é deixar as classes por definir mesmo e puxar pelo poder de abstracção dos alunos.
Uma figura consiste numa colecção de formas:
class Posição {public:Posição(double const x, double const y);
double x() const;double y() const;
private:double x_;double y_;};
class Dimensão {public:Dimensão(double const largura, double const altura);
double largura() const;double altura() const;
private:double largura_;double altura_;};
class Caixa {public:Caixa(Posição const& posição, Dimensão const& dimensão);
Posição posição() const;Dimensão dimensão() const;
private:Posição posição_;Dimensão dimensão_;};
list<Forma*> figura;
Suponhamos apenas as formas específicas Quadrado e Círculo.  O que é uma forma?  Como representá-la?
O conceito de  Forma é abstracto!  Já os conceitos
de  Quadrado ou Círculo são bem concretos!
Podemos ver o conceito de  Forma como uma generalização
dos conceitos de Quadrado, Circulo, etc.  O que é que é
possível fazer com qualquer forma?
Discutir. Concluir:
Discutir membros!
class Forma {public:Forma(Posição const& posição);
double área() const;double perímetro() const;Posição const& posição() const;Caixaconst caixaEnvolvente() const;
void movePara(Posição const& nova_posição);
private:Posição posição_;};
Forma::Forma(Posição const& posição): posição_(posição)
{}
Posição const& Forma::posição() const
{return posição_;}
void Forma::movePara(Posição const& nova_posição)
{posição_ = nova_posição;}
É muito
importante perceber que, devido a Forma ser um conceito abstracto, não
é possível implementar as operações para cálculo da área, do perímetro e
da caixa envolvente. 
Claro está que para uma forma concreta, como círculo, isso já é
possível.  Para já, no entanto, vamos discutir o caso
da posição.
Todas as formas têm uma posição. A posição é dada tipicamente pela posição de um ponto importante da forma, que pode ser o centro de um círculo ou um foco de uma elipse, um dos cantos de um quadrado ou rectângulo, o centro geométrico de um triângulo, ou um dos seus vértices, etc.
Por isso faz sentido definir um atributo para guardar a posição e implementar
operações para inspeccionar e alterar o seu valor (mover para) na classe
Forma!
Outra questão importante é que operações devem ser polimórficas. Claramente deverão ser:
área()
perímetro()caixaEnvolvente()E
as operações relativas à posição? 
É discutível.  Quando se desenha uma classe base de
uma hierarquia de classes há que ter o espírito aberto! 
Será que alguém alguma vez pode querer definir uma classe
derivada de  Forma que tenha uma maneira diferente de se mover?  É
discutível.  Mas em geral em geral é má ideia tornar polimórficas
as operações inspectoras que se limitam a devolver o valor de um
atributo.  E quanto à operação modificadora?  Vamos admitir que
queremos deixar em aberto a possibilidade de alguém especializar a forma como
uma forma se desloca.
Ou seja:
Notar destrutor virtual!
class Forma {public:Forma(Posição const& posição);
virtual ~Forma() {}
virtual double área() const;virtualdouble perímetro() const;Posição const& posição() const;virtualCaixa const caixaEnvolvente() const;
virtual void movePara(Posição const& nova_posição);
private:Posição posição_;};
E a classe  Círculo?  Um  Círculo é uma
 
Forma que, para além da posição que todas as formas
têm (que corresponde ao centro do círculo), tem um raio. 
Logo: 
Discutir operações.
class Círculo : public Forma {public:Circulo(Posição const& posição, double raio);
virtual double área() const;virtual double perímetro() const;virtual Caixa const caixaEnvolvente() const;double raio() const;
private:double raio_;};
Círculo:: Circulo(Posição const& posição, double raio): Forma(posição), raio_(raio)
{}
doubleCírculo::área() const
{return 2.0 * pi * raio();}
doubleCírculo::perímetro() const
{return pi * raio() * raio();}
Caixa const Círculo::caixaEnvolvente() const
{return Caixa(Posição(posição().x() - raio(),posição().y() - raio()),Dimensão(2.0 * raio(), 2.0 * raio());}
doubleCírculo:: raio() const
{return raio_;}
Note-se que o inspector do raio não é polimórfico. Com isso deixa-se uma mensagem clara a quem queira especializar círculos: não deve especializar esse inspector. O método fornecido é definitivo e não pode ser especializado.
Mas há aqui ainda um problema.  Para que uma operação como caixaEnvolvente() possa ser usada para qualquer
 Forma da  Figura tem de
estar declarada na classe base, claro.  Mas não pode ser definida,
pois só sabemos calcular a envolvente de formas concretas!  Ou seja,
a classe Forma fornece uma operação caixaEnvolvente(),
mas não fornece nenhum método que a implemente!
Tal como as coisas estão obteremos um erro de fusão: o fusor vai-se
queixar que não encontra a definição dos métodos Forma::caixaEnvolvente(),
Forma::área() e Forma::perímetro() da classe Forma!
Em C++ esta "bota" descalça-se indicando claramente que não é suposto estas
operações serem implementados pela classe Forma: são abstractas
ou puramente virtuais, i.e., não têm método definido na classe, o que
é o mesmo que dizer que a classe se pode limitar a declarar essas operações,
não fornecendo a respectiva implementação:
class Forma {public:Forma(Posição const& posição);
virtual ~Forma() = 0;
virtual double área() const = 0;virtual double perímetro() const = 0;Posição const& posição() const;virtual Caixa const caixaEnvolvente() const = 0;
virtual void movePara(Posição const& nova_posição);
private:Posição posição_;};
Forma::~Forma()
{
}
Desenhar diagrama no quadro:

Regras:
Notar que é comum uma classe abstracta ter o destrutor não apenas polimórfico mas também abstracto! Isso garante que a classe seja abstracta mesmo que se decida que todas as restantes operações sejam simplesmente polimórficas, e não abstractas.