Pessoal, boa tarde.
Hoje é dia 27 de julho de 2020,
uma segunda-feira, quase 16 horas.
Estamos aqui pra falar do Grupo de Slides número 11 parte A.
Aonde a gente trata de Herança et al.
Na verdade, a gente vai tratar de funções virtuais,
polimorfismo que tá ali salientado,
herança múltipla, funções virtuais puras
e classes abstratas.
Todos esses elementos aqui dependem de herança, no final das contas, em alguma medida.
Já de antemão eu adianto que
possivelmente essa é a aula mais importante do curso.
Há parte de literatura que diz que a orientação a objetos
não seria orientação a objetos sem o polimorfismo.
Aí está.
Começamos com um exercício.
Criar uma lista no sistema,
Sistema Acadêmico, obviamente,
com todas as pessoas criadas
independentemente de suas especializações, Professor ou Aluno.
Na classe Professor, criar um atributo Salario,
criar um atributo BolsaProjeto e o método InformaProventos.
Criar uma classe Estagiario derivada de Aluno
com um atributo BolsaEstudo e um método InformaProventos.
Isso considerado, avancemos pro próximo slide aqui.
A gente vai se concentrar
no primeiro elemento do exercício.
Criar uma lista no Sistema Acadêmico
de todas as pessoas criadas independentemente de suas especializações.
Então, voltamos aqui ao modo exibição,
destacando esse primeiro item do exercício 1.
Tá aqui o início da solução.
Novamente, eu vou ler o exercício.
Criar uma lista no sistema
com todas as pessoas criadas independentemente
de suas especializações (Professor ou Aluno).
Aqui, eu tô criando um objeto LPessoas
que é do tipo Lista parametrizado com Pessoa.
Prestem atenção que essa aqui é a versão do sistema
aonde, ainda, a gente tem as listas com algum acoplamento.
Eu não estou usando aquela versão
que tratou o Grupo de Slides 11 parte B.
Aonde, em vez de você ter aqui, por exemplo, uma Lista parametrizada com Universidade,
você já ia ter uma ListaUniversidade
cuja essência ia ser uma Lista parametrizada com Universidade.
Bom, a gente tá usando essa versão aqui que é um pouco mais acoplante,
e a gente vai ver o impacto que isso tem.
Muito que obviamente como vocês já podem prever,
parte de um exercício depois pra
no decorrer dessa apresentação vai ser que vocês
substituam essas listas aqui
por listas mais coesas, desacopladas
à luz do que foi feito no Grupo de Slides 10 parte B.
Esse aqui tá usando por enquanto a solução dada no Grupo de Slide 10 parte A.
Bem entendido.
Isso considerado,
tá aqui, ainda que com um nível de acoplamento,
tá aqui uma resposta pro exercício 1, item 1.
Criar uma lista no sistema com todas as pessoas criadas independentemente de suas especializações.
Parte da resposta tá aqui.
A gente sabe que conforme for criado nosso template,
se eu parametrizo o template Lista
com uma Pessoa, isso vai ser na verdade,
uma Lista de ponteiros de Pessoas.
Isso que o objeto LPessoas aqui vai tratar.
Bom, a criação dessa Lista
impacta em algumas inicializações.
Por exemplo, aqui, os Alunos
eles são pessoas, então aqui no InicializaAlunos,
além de colocar os Alunos numa eventual Lista de Alunos,
aliás ela existe aqui,
eu tenho que colocar também a Lista de Pessoas.
Quem mais é pessoa aqui?
Professores.
Os Professores muito embora não tenham lista
eles tem uma função de inicialização,
que tá aqui.
Essa função também vai ser impactada, porque lembra aqueles professores criados estaticamente
vão ter que ser jogados na lista de Pessoas.
Tal qual ocorre com os objetos Alunos,
os objetos de Aluno criados estaticamente aqui.
Vamos lá, então, pra prática.
Tá aqui o InicializaAlunos.
Eu criei dois ponteiros aqui aterrados,
é o ponteiroPessoa e ponteiroAluno.
Aqui eu coloco um nome no Aluno
criado estaticamente, triplo A, AAA.
Coloco o endereço desse Aluno na Lista de Alunos,
ainda naquela versão, insisto, tá,
com algum nível de acoplamento que a gente já discutiu, inclusive, com replicação
do nome no Elemento.
Aí, vocês vão depois, na base experimental de vocês,
modificar isso e usando uma lista altamente desacoplada,
insisto, novamente,
à luz do exposto no Grupo de Slides 10 parte B.
Tudo bem, isso considerado, o fato é que eu tô colocando o Aluno na Lista de Alunos.
Agora eu quero colocar o endereço desse Aluno numa lista de Pessoas.
Para tal eu tô armazenando esse endereço no ponteiroAluno,
eu poderia fazer essa conversão de apontamento, aqui, ó.
Fazer o ponteiroAluno apontar
pra aquele endereço enquanto apontamento de Pessoa,
usando um cast tradicional
ou eu posso... isso tá comentado,
ou eu posso fazer, então, um cast mais seguro.
Aqui eu tô usando um static cast
que permite eu converter um apontamento
enxergar um endereço que aponta pro Aluno
enquanto um apontamento de Pessoa
e eu quero armazenar aqui no ponteiroPessoa.
Depois desse endereço, eu apago esse endereço
tô enxergando todo acesso à parte de Pessoa
do Aluno em questão, o triplo A,
ele é armazenado na Lista de Pessoas.
Aqui, dizendo entre aspas,
de maneira bastante alto nível,
com uma certa licença poética,
é como se eu tivesse convertendo o Aluno pra Pessoa e jogando na Lista de Pessoa, tá.
Claro que aqui a gente sabe que esses endereços são ponteiros, bem entendido.
Quando eu aponto um Aluno a partir de um ponteiro Pessoa,
o que significa?
Significa que esse apontamento
só enxerga a parte Pessoa do Aluno.
O Aluno não perde a parte de Aluno dele, continua existindo lá.
Só que esse ponteiro em questão enxerga só a parte de Pessoa.
O ponteiroAluno, por exemplo, enxerga tudo.
Enxerga tudo do Aluno.
Enquanto que o ponteiroPessoa enxerga só a parte de Pessoa do Aluno.
Bom, esse vislumbre
do Aluno enquanto Pessoa
é armazenado na lista de Pessoas.
Depois eu uso o mesmo procedimento
pro triplo B que é armazenado na lista de Alunos.
Tem essa conversão, aqui, de apontamentos.
e o endereço é jogado dentro da lista de Pessoas.
Aqui eu sempre faço esse código de uma maneira bastante pedagógica, tá.
Mas eu poderia fazer aqui uma coisa muito mais simples.
Eu poderia, por exemplo, simplesmente colocar aqui,
no incluaInfo já o endereço do triplo B direto aqui, ó.
&BBB.
Ele iria funcionar, iria fazer conversões automáticas.
O problema das conversões automáticas
é que você perde a segurança que você tem no static cast.
Aqui no static cast como eu tô fazendo passo a passo
esse static cast ele faz uma certa avaliação
analisando a clausabilidade da conversão.
Através das tipagens
ele vê se é plausível esse tipo de conversão.
Inclusive, tem mais... além do cast tradicional
esse cast que da linguagem C++ herdou da linguagem C.
Então, além desse cast ou forjamento tradicional
você tem outros tipos de cast em C++
que são mais ou menos seguros.
O static cast é o típico cast
que da uma certa segurança pra ver... analisando um pouco a clausabilidade da conversão.
Inclusive, já fica como atividade pra vocês estudar
mais afinco essa questão do static.
O fato é que nesse static_cast e dos cast's no geral.
além do static cast você vai ter, por exemplo,
o dynamic_cast e o reinterpret_cast.
O que interessa aqui pra nós em todo caso nesse momento preciso,
é que aqui eu consigo, com uma certa segurança,
converter apontamentos de Aluno
para apontamento de Pessoa,
usando essa sintaxe aí.
Aqui, o triplo C, mesma coisa.
Essa Pessoa recebe o nome, o endereço dela é armazenado
na lista de Alunos, depois esse endereço é armazenado no ponteiro de Aluno,
eu converto esse ponteiro de Aluno pra um ponteiro de Pessoa,
e armazeno o endereçamento de Pessoa lá na lista de Pessoas.
Mesma coisa no triplo D.
Olha aqui o static_cast que também tá sendo aplicado ao triplo D.
Aqui, na verdade, tá, gente,
o static_cast, na verdade, é uma função,
static_cast é uma função
que recebe como parâmetro o ponteiroAluno
e retorna algo,
que vai ser o ponteiro de Pessoa.
Como é que ele sabe que é pra retornar o ponteiro de Pessoa?
Por causa do parâmetro, aqui, de tipagem
que essa função recebe.
Tal qual uma classe
pode receber parâmetros de outro tipo.
Como a classe Lista que é parametrizada com um tipo
Funções, em C++,
elas também podem ser template.
e ser parametrizada com um tipo.
Dizendo mais uma vez.
Assim como uma classe pode ser template e parametrizada com um tipo,
funções soltas, procedimentais em C++,
elas podem, além de receber os parâmetros usuais,
elas podem, também, serem parametrizadas com um tipo.
O que faz com que elas sejam funções template.
Então, além de classe template, você tem a função template, bem entendido.
Bom, isso considerado,
tá aqui o triplo E, o último Aluno,
criado estaticamente.
Recebe um nome interno ali.
O endereço dele é incluído na lista de Alunos
e o endereço é armazenado, aqui, pedagogicamente, num ponteiroAluno.
Esse ponteiroAluno é jogado pra essa função static_cast,
função template, trabalha com ponteiro de Pessoa,
que vai permitir fazer, no final das contas, no âmbito dessa função aqui,
ou um comando se quiser enxergar assim, tá,
a conversão ponteiroPessoa
e daí esse endereço enxergado
enquanto Pessoa é armazenado na lista de Pessoas
ou na lista de apontamentos de Pessoas, bem entendido.
Bom, só que os Alunos
eles não são apenas criados estaticamente.
Nessa versão que a gente tá fazendo, nesse experimento que a gente tá fazendo,
nesse Sistema Acadêmico aqui, né.
Pro nosso ambiente de ensino aqui pedagógico,
ele tem Alunos criados estaticamente,
esses que vocês tão vendo aí, AAA, BBB, CCC, DDD e o EEE,
mas ele também tem os Alunos que são criados dinamicamente,
conforme os requisitos que foram apresentados nos slides anteriores.
Então, se você olhar aqui,
você vai ter o cadastro de Aluno aqui, ó.
É criado próprio pra criação de Alunos dinamicamente.
Isso aqui já foi visto em aulas anteriores.
Tem ali um vetorzinho de caracteres, um RA como inteiro,
ponteiroAluno, ponteiroPessoa.
Agora, essa função cadAluno, naturalmente, ela evoluiu, né.
Por exemplo, antes não tinha esse ponteiroPessoa.
Pergunta o nome do Aluno.
Pergunto o RA do Aluno.
Crio dinamicamente um Aluno aqui
que é apontado pelo ponteiroAluno,
que é esse apelido temporário dele no âmbito dessa função.
Coloco, através desse ponteiro um nome no Aluno criado, um RA,
o id ele já recebeu pela construtora.
e eu incluo daí o endereço desse Aluno criado aqui,
incluo na lista... esse endereço na LAlunos.
Graças a esse ponteiro que fica armazenando, temporariamente, esse endereço.
Uma vez que esse endereço é armazenado na LAlunos esse endereço
sobrevive durante a execução do sistema, né,
lá no apontamento dado.
Lá, perdão, lá na lista dada que é LAlunos.
Aqui, daí, eu faço o quê?
Vou pegar esse ponteiro de Aluno,
fazer uma conversão agora pra ponteiroPessoa, por assim dizer,
usando o static_cast.
Eu coloquei até aqui uma licença de discurso que é a seguinte.
Logo abaixo a forma moderna de fazer cast;
e usando o static_cast.
Aqui tá comentado esse código, tá.
Logo abaixo a forma antiga
e desaconselhável de fazer o cast.
Por que que isso aqui seria desaconselhável?
Porque esse cast tradicional aqui, ele funciona, tá,
mas ele é um cast que ele converte a fórceps.
Ele não faz nenhuma análise da clausabilidade da conversão.
Aqui eu tô, então, daí, uma vez convertido, né,
bem entendio que a gente tá usando esse cast mais plausível, aqui,
jogo o endereçamento na LPessoas.
O endereço vai ser enxergado, agora, no viés,
só da parte Pessoa
do objeto Aluno em questão criado dinamicamente.
Bom, agora a gente já permite então, colocar na LPessoas os Alunos.
E os Professores, não merecem estar na LPessoas? Merecem.
O exercício manda colocar qualquer Pessoa na lista de Pessoas.
O que a gente tem como Pessoa são Alunos e Professores.
Então os Professores também tem que entrar nessa lista.
E aqui tá, pessoal.
InicializaProfessores.
Tenho aqui um ponteiroPessoa e um ponteiroProfessor.
Poderia aterrar com nulo, tá. Façam aí depois.
Aqui eu tô fazendo os inicializas dos professores que vocês já conhecem.
Associando eles a Departamento.
Do ponteiroProfessor tá recebendo aqui
o endereço do Simão.
Converto o ponteiroProfessor pra ponteiroPessoa, por assim dizer
e armazeno o endereçamento
que tá em ponteiroPessoa na LPessoas.
Faço também a mesma coisa pro Einstein e pro Newton.
Isso vai garantir que a LPessoas também tenha os apontamentos
de Professor além dos apontamentos de Alunos.
Só que na LPessoas ele enxerga só a parte Pessoa dos Alunos
e só a parte Pessoa dos Professores, insisto.
Aqui tá o Menu Executar.
Vejam que no MenuExe é da classe Principal, já conhecido de vocês, tá.
Agora eu criei uma opção a mais que é o Listar Pessoas.
Vocês já tinham o Listar Disciplinas, Departamentos, Universidades,
Alunos, Professores e ficou... faltou um 's' no código, depois vocês colocam
e agora tem também a opção 6 que é a Listar Pessoas.
case 6: eu vou lá e chamo o listeInfos no LPessoas.
Aqui eu tô usando aquela versão que é a de replicar
dentro do Elemento o nome das Pessoas, tá.
A hora que vocês fizerem o exercício
que vai ser trocar por listas mais desacopladas
aqui vai ter uma modificação naturalmente.
Isso considerado,
apesar de eu estar utilizando essa replicação dentro do meu Elemento
a questão funciona, tá.
E tá aqui, ó.
Então, eu consigo listar todas as Pessoas.
Com todo o ou's que tenha replicado dentro de Elemento, bem entendido.
Na versão que vocês vão fazer, vai ter o mesmo resultado,
só que a luz de toda a coesão e desacoplamento.
Muito bem.
Aqui eu tô lembrando que eu tô usando uma API pra fazer esse pause aqui.
Já foi discutido em slides anteriores.
É uma APIzinha relativa ao DOS.
Muito bem. E aqui a gente venceu o primeiro tópico do exercício que era
Criar uma lista no sistema com todas as pessoas
criadas independentemente de suas especializações (Professor, Aluno).
Com a ressalva de ser essa versão com algum nível de acoplamento que
a versão melhorada de vocês vai, justamente, resolver criando
listas altamente coesas e desacopladas a luz do já discutido anteriormente.
No item dois.
Na classe Professor criar um atributo Salario,
criar um atributo BolsaProjeto e um método InformaProventos
que é o item que a gente vai trabalhar agora.
Então, a gente vai criar, na classe Professor, criar um atributo salário
que não tinha
e criar mais um atributo
BolsaProjeto que também não tinha
e um método informaProventos, tá,
que, naturalmente, ele vai informar o resultado de salário mais bolsaProjeto.
Então tá aqui salário e bolsaProjeto.
São floats na classe Professor ela é derivada de Pessoa.
set e getSalario, set e getBolsaProjeto
e informaProventos.
Os sets e gets são óbvios.
Eu até coloquei aqui o setSalario e o getSalario como exemplo,
o resto vai tá nas reticências.
O informaProventos também não tem nada de extraordinário, tá.
Inclusive, se você olhar no inicializa que é chamada na construtora,
salario e bolsa_projeto recebem zero.
Inicializa é chamada nas duas construtoras,
nas duas esses caras estão sendo zerados.
Aqui, obviamente, tá, tem mais código.
Com certeza, basta você olhar os códigos que estão disponíveis no site, tá.
Porque certamente eu também tô fazendo o aterramento dos ponteiros
que já estavam lá em códigos anteriores.
Eu só tô colocando essas reticências pra não ter sombra de dúvida que isso ocorre.
Muito bem.
Então tem aqui o inicializa
que zera o salario e bolsa_projeto e também vai aterrar os,
certamente, os ponteiros que estão lá.
E aqui tem o informaProventos, de forma tal que se eu não usar
um setSalario e um setBolsaProjeto
pra modificar o valor inicial
ele vai informar zero.
Mesmo porque ele diz o seguinte aqui no informaProventos.
O valor dos proventos do Prof. Tal
seria, ou é, né, tanto.
E esse tanto é salario + bolsa_projeto.
É uma função bastante evidente aqui.
Agora essa função, aqui, informaProventos vai ser bem importante pra nós.
Inclusive, lá no inicializa Professores, tá,
eu tô usando os sets e, justamente,
pra inicializar bolsa_projeto, o Simão tem lá 1000 unidades de valor,
relativo a uma bolsa de projeto
e tem mais, supostamente, aqui nesse exemplo,
4000 unidades de valores no salário.
Já o Einstein 25000 unidades de valores como salário,
e o Newton 25000 unidades de valores como salário,
muito embora não tem bolsa.
Então, o atributo deles bolsa vai ficar com zero,
naturalmente vai ficar com zero, porque assim reza a construtora.
Já que eu não chamei em nenhum momento o set.
Legal, e com isso a gente resolveu o tópico 2 do nosso exercício que tá aqui.
Perdão, deixa eu voltar ali.
Tá aqui.
Não é isso?
E agora tem o tópico 3.
Criar uma classe Estagiario,
classe derivada de Aluno,
com atributo BolsaEstudo e InformaProventos.
Os proventos no caso do estagiário aqui,
vão ser só o informar o valor de BolsaEstudo, bem entendido.
Podia chamar de BolsaEstagio
mas, enfim, o exercício tá rezando que seja BolsaEstudo,
vamos respeitar esse requisito aí.
Estagiario que deriva publicamente de Aluno, né.
Você criou ali... essa classe não existia, tá, essa é uma classe nova.
Mas ter a classe, pra vocês, atualmente, já é algo evidente.
BolsaEstudo aqui que é um atributo float, né,
real, protegido.
Tem uma construtora com parâmetros respeitando a construtora da classe Aluno
que por sua vez respeita a construtora da classe Pessoa.
Uma construtora sem parâmetro e a destrutora.
Tem o inicializa, setBolsaEstudo, getBolsaEstudo,
e o informaProventos, nada de extraordinário.
Se isso aqui é o .h, tá aqui o respectivo .cpp, naturalmente.
Então, aqui, a partir da construtora com parâmetros,
eu chamo a construtora da classe base, repassando os parâmetros da construtora na classe base, né.
Obviamente, aqui, eu tô chamando a construtora com parâmetros inevitavelmente.
Depois lá, internamente, eu chamo o inicializa.
Aqui, no Estagiario,
a construtora sem parâmetros tá chamando explicitamente a construtora sem parâmetros também
que é uma boa prática, conforme a gente já discutiu.
Chama a função inicializa.
Destrutora vazia que não faz nada,
mas a gente tem que ter por motivos já explicados.
O inicializa coloca o BolsaEstudo como 0.
Tenho o setBolsaEstudo se eu quiser atribuir valor,
e um getBolsaEstudo se eventualmente precisar.
E aqui tem o informaProventos,
O valor de BolsaEstudo do Aluno fulano de tal.
Professor, mas como é que ele tem nomeP aqui, se não tá lá?
Ué, estagiário é derivado de Aluno e Aluno é derivado de Pessoa,
e na Pessoa o atributo nome é protegido.
Bem entendido, então eu tenho acesso aqui.
Se é protegido na Pessoa,
continua protegido no Aluno
mesmo porque o Aluno derivou publicamente da Pessoa.
E aí, o estagiário deriva publicamente do Aluno
absorve o que é protegido do Aluno
e o que Aluno absorveu de Pessoa, naturalmente.
Então, aqui, o Estagiario e seu atributo nome
é herdado em duas gerações, por assim dizer, né.
O Estagiario derivou de Aluno e o Aluno derivou de Pessoa, insisto.
Assim, o Estagiario também é uma Pessoa além de ser um Aluno.
Bem entendio.
Aqui na Principal, pra fins de exemplo, tá.
Eu tô criando um Estagiario Fulano e um Ciclano.
Tô destacando que existe a LPessoas.
Tem vários outros códigos que eu não tô destacando.
Tem aqui o InicializaEstagiarios que é um funçãozinha nova que eu criei.
O que faz a função InicializaEstagiarios?
Tem um ponteiro de Pessoa, um ponteiro de Aluno e um ponteiro de Estagiario.
Fulano vai receber um nome interno lá, que vai ser Fulano
vai ser Fulano Fulano, ou Fulano Ciclano, sei lá eu,
enfim, eu pus um nome interno pra ele aqui.
Aqui, eu tô pegando o valor de bolsa de estagio,
800 unidades de valores.
Muito bem, agora o Fulano tá inicializado.
Objeto estático criado.
Agora eu vou armazenar esse ponteiro do Fulano nesse ponteiroEstagiario.
Vou, por assim, converter esse ponteiroEstagiario
em ponteiro de Aluno, usando static_cast.
e tô fazendo esse Estagiario ser armazenado no ponteiroAluno.
Ah, professor, eu não concordo que o Estagiario seja armazenado na Lista de Alunos,
acho que não tem nada ver, ele não devia ser armazenado.
Nesse código foi interpretado assim, tá.
Isso aqui é só um exemplo pedagógico.
Só pra mostrar que eu posso pegar o Estagiario, converter em Aluno
e armazenar ele na lista de Alunos.
Ademais, eu posso pegar, agora, o Estagiário apontado pelo ponteiroAluno
converter em Pessoa e jogar na Lista de Pessoas.
Eu também podia fazer direto. Eu podia pegar direto
o ponteiroEstagiario converter diretamente em Pessoa e jogar numa Lista de Pessoas.
O fato é que agora, tanto Fulano quanto Ciclano, passam pelo mesmo processo,
de conversões, tá.
Os endereçamentos deles estão armazenados na Lista de Pessoas.
Nesse momento, a Lista de Pessoas
passa a ter apontada, né, ou registrada dentro de si
os endereços de Alunos, Professores e Estagiários,
mas, novamente, à priori ele só enxerga a parte Pessoa desses caras.
Mesmo o Estagiário que além de Estagiário também é Aluno e também é Pessoa.
Ele vai enxergar só a parte Pessoa do ponto de vista da lista de Pessoas, bem entendido.