Pessoal, bom dia.
Professor Simão falando. Estou em Curitiba.
Uma manhã do dia 9 de julho de 2020.
Estamos aí pra falar do Grupo de Slides número 3 parte B.
Aonde a gente fala do Relacionamento de Herança.
A gente já tratou, no tocante a classes,
o relacionamento de agregação forte e fraco,
o relacionamento de associação
e agora a gente vai falar do relacionamento de herança
que também é muito importante.
Muito bem, deixe-me colocar em Modo Exibição aqui.
Vamos passar pro slide 2
desse Grupo de Slides sobre herança.
Introdução a Herança.
Fazer uma reflexão sobre o que a gente tem elaborado até então.
Está correto semanticamente falando,
ou seja, em termos de significado,
que os objetos Simao, Einstein e Newton
sejam da classe Pessoa?
Eles não seriam, na verdade, de uma classe Professor?
Entretanto, eles não seriam também Pessoas?
No meu caso, eu como professor,
eu sou o Professor Simão ou sou a Pessoa Simão?
Na verdade, ambos, né.
Só que ainda sim tem uma especialidade
que é o fato de eu ser professor,
que pra um Sistema Acadêmico isso é pertinente.
Herança. Com o mecanismo de herança pode-se fazer
com que um objeto pertença a duas classes.
Até mais, na verdade, tá, mas aqui é só pra introduzir o conceito.
Isto é possível definindo
que sua classe herde as propriedades
de uma classe base.
Ou mais classes bases, mas, novamente,
aqui a gente está só introduzindo o conceito.
Então, de maneira mais pedagógica,
tá aqui um exemplo bem pontual que é
o exemplo dado ali, tá.
Você tem classe Pessoa
e agora você também tem a classe Professor.
Vejam que agora a classe Pessoa
não tem mais nada que seja pertinente a Professor.
No âmbito estudado
o que é pertinente a Professor é o fato de ele ter uma Universidade associada
e um Departamento associado.
Não é toda Pessoa que vai estar relacionada com Universidade, né.
Agora Professor sim, Professor vai tá peculiarmente associado com Universidade, tá.
Então, respeitando os requisitos dados até então,
ou os exercícios dados até então,
você pode aceitar tranquilamente
que isso está bem razoável, tá. Você tem aqui, ó,
pUnivFiliado ponteiro de Universidade,
pDptoFiliado ponteiro de Departamento, mas agora na classe Professor.
E não mais na classe Pessoa, Pessoa não tem esses ponteiros.
Pessoa tem o que é pertinente a Pessoa.
diaP, mesP, anoP, idadeP, nomeP e até um identificador aqui
que aparentemente eu coloquei visando já alguma atividade futura.
Tem aqui a construtora com parâmetros, a construtora sem parâmetros, a destrutora
e as demais funções-membro ou métodos.
Ó o ponto e vírgula que termina a classe ali, tá.
Muito bem.
Aí agora você tem a classe Professor.
A classe Professor vai ter o que é pertinente a Professor.
Você poderia ter aqui, por exemplo, um número, Siape,
enfim, o número de registro do Professor.
Poderia ter outros atributos, tá, particularmente se os
exercícios anteriores tivessem solicitado algo assim.
Aqui o fundamental é entender que a classe Professor agora
herda, isso significa, herda de Pessoa.
Significa que além de ter tudo o que o Professor tem,
ela tem tudo o que a Pessoa tem.
Ela herda da classe Pessoa,
Então a hora que eu crio, por exemplo, Simao do tipo Professor,
ele vai ser Professor e Pessoa.
Olha só a construtora aqui do Professor.
Quando eu herdo uma classe de outra
eu tenho que na classe derivada
respeitar os construtores da classe base
que é o que tá acontecendo aqui.
Eu tenho aqui uma construtora com 4 parâmetros
pra respeitar a construtora da classe base
e tenho uma outra construtora aqui sem parâmetros,
pra respeitar a construtora sem parâmetros,
mesmo porque é regra ter construtora sem parâmetros,
e tenho aqui a destrutora que também é regra ter destrutora, nada demais.
Me permita fazer uma pequena correção aqui.
Vejam inclusive aqui, ó, fazendo essa correção
como na classe base o parâmetro tem valor default
eu respeito isso aqui também na classe derivada.
O que mais que vai ter aqui na classe derivada?
Vai ter setUnivFiliado(), setDepartamento(),
a função OndeTrabalho(),
e a função QualDepartamentoTrabalho().
Que eram já funções relativas a esses atributos,
mas que antes estavam, vamos dizer, mal colocadas
lá na classe Pessoa e agora estão bem colocadas em uma classe própria
que é a classe Professor.
Sistema orientado a objetos, tá, e tanto o desenvolvimento
que envolve a modelagem e a programação orientada a objetos
elas demandam esse refino, você vai refinando o modelo,
provavelmente, orientado por um parâmetro de custo-benefício.
Muito bem.
Se vocês olharem aqui a classe Pessoa
ela tá aqui como protegido. Tá vendo, ó? Não tá mais privado.
Então, na verdade, você, em C++,
você tem três possibilidades de classificar
ou de enquadrar melhor dizendo
os seus atributos e métodos.
Podem ser, em tese, bom, na prática também, mas
eles podem ser privados, protegidos e públicos.
Ainda que você tenha uma tendência
que os atributos, via de regra, sejam privados ou protegidos, tá,
e as funções a maior parte, provavelmente, vai ser pública,
mas nada impede que haja também funções privadas.
Indo ao ponto, qual é a diferença entre um elemento privado e protegido?
Que é a pergunta que tá posta aqui embaixo.
A diferença é que o elemento privado não é herdado diretamente,
enquanto o protegido é herdado.
Então, vejam aqui a função, OndeTrabalho()
a função OndeTrabalho() ela usa um nome
ela vai falar: "o fulano de tal trabalha pra tal universidade".
Então, esse fulano de tal que é utilizado aqui na OndeTrabalho()
ele vem do atributo nome.
Para que a função OndeTrabalho() possa acessar diretamente o atributo nome
na classe base esse atributo tem que estar classificado como protegido.
O protegido ele é um privado melhorado, tá.
Tudo continua sendo privado com a ressalva que
nas classes derivadas você consegue acessar diretamente o atributo
nas funções pertinentes, tá.
Então, insisto, aqui, por exemplo, tá,
as duas funções aqui OndeTrabalho() e QualDepartamentoTrabalho()
acessam o atributo nome.
Como Professor é derivado de Pessoa
Professor é uma Pessoa e vai ter um nome.
Agora no âmbito da classe Professor,
eu consigo utilizar diretamente
esse atributo que foi herdado da parte de Pessoa, porque ele é protegido.
Se ele fosse privado lá na classe Pessoa,
aí pra eu utilizar aqui eu teria que chamar o getNome().
Eu teria que fazer um acesso indireto, bem entendido.
Mas tudo bem.
A tendência é quando você for fazer classes que vá servir
de base de migração pra outros
é usar, então, ao invés de privado, usar protegido ali
e faz esse efeito que eu já expliquei.
Tá, aqui tem o Pessoa.h e tem o Professor.h.
Não é isso?
Se o Professor, a classe Professor é derivada da classe Pessoa,
é natural então que eu faça ali um #include "Pessoa.h",
pra eu poder fazer essa derivação justamente,
pra essa classe saber da onde buscar
o código pra criar a derivação, bem entendido.
Aqui nós temos o Pessoa.cpp. Normal. Não muda nada.
Salve o fato que obviamente
não tem mais as funções agora que são relativas a parte
de Professor, justamente, porque essas funções estão no Professor.cpp.
Então, tá aqui o Professor.cpp.
Vejam que interessante.
A construtora do Professor
ela coloca dois pontos aqui, ó,
e chama a construtora da classe base.
Aqui a mesma coisa, ó.
A construtora sem parâmetros, dois pontos e chama a construtora da classe base.
Esse espaço entre os dois pontos e o início da implementação
serve pra duas coisas.
Chamar a construtora de classe base
ou construtora do objeto agregado.
Conforme a gente já viu em aula precedente.
Inclusive, você pode chamar a construtora da classe base e do objeto agregado, tá,
colocando aqui vírgula entre cada chamada
sendo que a última chamada fica sem vírgula.
Aqui só tem uma chamada, então, sem vírgula, naturalmente, tá, porque ela é a última.
Aqui, o que a gente tá fazendo nessas construtoras, tá.
Em todas elas a gente tá aterrando os ponteiros.
É ou não é?
E repassando os parâmetros para construtora base.
Ó, diaNa, é passado pra Pessoa.
Vejam que não tem o int aqui, tá, pessoal.
Porque aqui eu não tô redefinindo um parâmetro eu tô
passando um parâmetro que já foi definido ali, ó:
mesNa, passado aqui; anoNa passado ali;
nome, repassado acolá.
Construtora sem parâmetro.
Não tem parâmetro? Ainda assim, eu chamo a construtora explicitamente, tá.
Novamente, tenham como hábito, chamar as construtoras explicitamente, tá.
Na versão de código, que você tá fazendo aí na sua casa,
na sua base experimental,
se eventualmente você percebe que tem um construtora
que não tá sendo chamada explicitamente, explicite ela.
Essa é uma excelente regra, um excelente hábito
que você cria e vai lhe evitar um monte de problemas.
Aqui tem o setUnivFiliado(), o setDepartamento(),
o OndeTrabalho() e o QualDepartamentoTrabalho().
Tá ali, ó, o OndeTrabalho().
Fulano de tal trabalha para
ele pede pra própria Universidade apontada informar o seu nome, né,
naquela colaboraçãozinha entre o objeto em questão
que é um objeto da classe Professor
e a Universidade que supostamente ele é filiado.
Aqui, poderia testar, se o ponteiro, tá... fazer um if aqui, tá.
Se esse ponteiro não é nulo.
Se o ponteiro for nulo, ou seja, se não existir a relação entre Professor
e Universidade, esse código dá erro.
Então, seria importante ter um if aqui, ó,
Testando if pUnivFiliado diferente de NULL, tá.
Isso é importante. Mesma coisa aqui, tá.
Aqui eu teria que testar os dois ponteiros ao bem da verdade.
Não é isso?
Mas isso é mais ou menos evidente suponho.
O fato, mais pertinente aqui, em todo o caso, que
o nomeP é acessível aqui diretamente,
porque lá na classe Pessoa ele é protegido e não privado.
Se ele fosse privado lá na classe base, eu teria que usar aqui ao invés de nome
diretamente a função aqui, getNome() pra poder acessar.
Então, aqui aconteceu que agora tá mais organizado.
Eu tenho a classe Pessoa e tenho a derivada da classe Pessoa
a classe Professor.
O que me leva, lá na classe Principal,
criar objetos, agora, de Professor
e não mais de Pessoa.
E aí, o Simao, por exemplo,
o Simao é um Professor, mas também é uma Pessoa.
Então, a partir do Simao eu posso chamar todas as funções
que são do Professor e que também tem em Pessoa.
Eu posso, antes de fazer Simao.OndeTrabalho(),
tal qual eu posso fazer Simao.getNome(),
posso fazer Simao.Calc_Idade() passando os parâmetros corretos, né,
e assim vai, bem entendido.
Muito bem.
Aqui em termos então de instanciação, né.
Aqui eu mostrei, voltando um slide, tá,
dois slides aliás, mostrei como é que você faz em código
e como é que você modela isso em termos de UML?