Pessoal, boa noite.
Aqui é o professor Simão falando.
Estou em Curitiba.
Hoje é dia 2 de julho de 2020.
Nós estamos aqui com o nosso curso de orientação a objetos.
Particularmente, com programação em C++ orientado a objetos.
Estamos no Grupo de Slides 1 - Parte B.
Esse Grupo de Slides 1 - Parte B
é intitulado: Passando à Prática Estrutura, Classes e Objetos.
Vamos para o slide 2, então.
Passando à Prática. Nosso primeiro exemplo irá transformar,
um programa C em um programa C++.
Eu acho essa aula particularmente interessante,
porque ela permite quiçá as pessoas que estão
acostumadas a programar de maneira procedimental
a serem sensibilizadas
sobre a diferença entre o programa procedimental
e um programa orientado a objetos.
Esse... Essa aula começa com uma proposição de exercício que tá aí exposto.
Eu vou ler rapidamente.
Criar um programa em C com os seguintes requisitos:
Crie um programa em C que permita calcular a idade de duas pessoas.
Para tal, crie uma struct Pessoa com 'campos' dia, mês, ano e idade.
Crie duas variáveis de Pessoa, chamadas Einstein e Newton
na função principal, a função main.
Ainda na função main,
faça os campos dia, mês e ano de Einstein e Newton receberem os valores apropriados.
Observação: Einstein nasceu em 14 de março de 1879
e Newton em 4 de janeiro de 1643.
O cálculo de idade se dará comparando o ano de nascimento com o ano atual.
Este cálculo se dará em uma função.
Esta função recebe como parâmetros de entrada:
a) uma variável Pessoa e b) uma constante inteira relativa ao ano atual,
ou supostamente... Suposto ano atual.
Essa função devolve a idade calculada, bem entendido.
Por fim, faça com que o campo idade de Einstein
e o campo idade de Newton recebam valores calculados
a partir de chamadas apropriadas da função citada.
Bom, isso considerado
vocês podem tomar um certo tempo pra fazer o exercício, parando o vídeo,
e depois vocês podem retomar o vídeo para ver a solução.
Eu aqui, ato contínuo, passo, então,
pra uma versão 1, pra eu por uma solução pra esse exercício.
Veja que pede pra fazer um programa em C,
então aqui seria uma revisão de programação em C
e depois a gente vai evoluir esse programa em C pra que ele se transforme num programa em C++
conforme objetivado nessa aula.
Tá aí, uma primeira versão.
Se você reparar pra atender os requisitos,
a primeira coisa que foi feita, foi criado aqui uma struct Pessoa
que tem os campos dia, mes, ano e idade todos inteiros.
Ainda que não tenha sido pedido nesse exercício, mas
eu poderia, hipoteticamente, ter outro campo
de outro tipo, né, que não inteiro,
por exemplo, nome, que podia ser um vetor de caracteres.
Aqui eu tenho uma função Calc_Idade,
cujo retorno é um inteiro,
e que tem dois parâmetros,
já adianto que são dois parâmetros por valor.
O primeiro parâmetro é um p do tipo struct Pessoa.
e o segundo parâmetro é um int ano.
Aqui dentro eu crio uma variável temporária, e local,
chamada idd do tipo inteiro.
idd recebe o valor de ano passado por parâmetro
e o valor de p.ano.
p é passado por parâmetro
é uma estrutura que vem por parâmetro e vem com seus campos, né.
Então, com dia, mes, ano e idade.
Aqui, no caso, eu vou
usar o valor que vem no campo anopp
pra fazer esse cálculo de ano - p.ano.
Isso vai ser armazenado em idd, e aí eu tenho o retorno idd.
É uma coisa bem básica pra quem estudou
linguagem C em disciplina precedente, isso é bastante evidente.
Aqui na função main, ao seu turno,
função main é a função principal de qualquer programa, como vocês sabem,
é usual que a função main retorne um inteiro,
e aqui tem um return 0. Isso significa, longa história curta,
que você está retornando pro sistema operacional, dizendo pro sistema operacional
que você tá retornando o problema com zero erros.
Bom, mas isso não é o nosso foco aqui, o nosso foco aqui é resolver o exercício.
Tem ali a estrutura, tem aqui o Calc_Idade,
que usa variável do tipo estrutura posta
pra fazer o cálculo conforme já explicado,
e aqui, tem a função principal.
Conforme o exercício propõe, eu tenho, então, as variáveis
Einstein e Newton, que são do tipo estrutura Pessoa.
Aqui eu coloco valores dia, mes e ano em Einstein,
respectivamente, 14, 3 e 1879.
Faço coisa similar com o Newton,
campo dia, mes e ano de Newton
inicializando, respectivamente, com 4, 1 e 1643.
O campo idade não foi inicializado, mas ele poderia e até deveria.
Podia ter aqui, por exemplo, um Einstein.idade recebendo -1, ou algo assim.
Não está inicializado. Felizmente que, logo em seguida,
eu já inicializo idade do Einstein a partir do valor...
Que valor é esse? É o valor calculado, justamente, pela função Calc_Idade.
Perceba que a função Calc_Idade,
que exige dois parâmetros, recebe dois parâmetros nessa chamada.
Nessa primeira chamada ela recebe o Einstein
ou seja, a variável do tipo estrutura, né, que tem quatro campos.
Recebe Einstein como primeiro parâmetro, e recebe aqui um suposto ano atual.
Aqui vocês podem, no exercício, obviamente, atualizar pra 2020.
Bom, aí vai acontecer o quê?
Vai calcular o valor da idade do Einstein do ano passado,
ou seja, no ano que foi passado por referência aqui, bem entendido.
E vai armazenar isso, via retorno, no campo idade de Einstein.
Por sua vez, o Newton no campo idade
vai receber o valor calculado pela função.
Que valor é esse? Ora...
O valor que vai ser calculado nessa segunda chamada da função
sendo que, nesse caso, é passado agora o Einstein (Newton) como primeiro parâmetro
e o suposto ano atual como segundo parâmetro.
É feito o cálculo e isso retornado aqui.
Depois através do printf usual
a gente imprime o valor de idade em Einstein e o valor de idade em Newton.
Aqui eu tô usando %d pra imprimir os valores, né,
porque são valores inteiros, tá.
Vocês podem usar %d ou %i, conforme vocês já sabem.
Bom, então, isso daqui é só... Isso aqui é uma primeira solução pra esse exercício dado.
Agora eu vou melhorar um pouco o exercício,
complicando um pouco o enunciado ou os requisitos do exercício, tá.
Mudar o programa segundo os novos requisitos.
Vou lê-los.
O cálculo da idade se dará comparando a data de nascimento com a data atual.
Este cálculo se dará em uma função.
Esta função recebe como parâmetros de entrada:
uma variável Pessoa; e três constantes inteiras relativas ao dia, mês e ano atual.
Esta função devolve a idade calculada.
Se você observar o exercício anterior, ele usava só o ano pra calcular a idade.
Só que usar só o ano pra calcular a idade de uma pessoa, ele dá uma idade imprecisa.
Eu, por exemplo, nasci em 1976,
e nós estamos no ano de 2020,
se eu fizer, 2020 - 1976, daria 44 anos,
mas como meu aniversário é só em outubro,
então, nesse presente mês de julho eu ainda tenho 43.
Então a gente vai fazer um cálculo pra....
Aliás, vai fazer uma mudança no nosso programa lá
pra melhorar esse cálculo em função aí dos requisitos postos.
Obviamente que agora vocês podem fazer uma pausa no vídeo se quiserem,
proporem uma solução, depois voltarem pra ver a solução que eu proponho aqui.
Ato contínuo, no meu caso, eu já vou mostrar a solução.
Voltamos, aqui tá o nosso programa.
Em tempo, esse programa aqui ele pode tá, num primeiro momento, todo num único main.c.
Não preciso, necessariamente, nesse momento, ter dividido o programa em vários arquivos.
Novamente, eu posso ter tanto a estrutura
quanto a função Calc_Idade e a função main num único programa.
Primeiro ia aparecer esse conteúdo,
depois esse conteúdo aqui da função Calc_Idade,
e, por fim, o conteúdo da função main.
"Professor, mas eu gosto de fazer as coisas um pouco mais modularizadas."
Não tem problema, você pode tá com esse main no main.c.
Esse main no main.c.
E essa estrutura Pessoa e esse Calc_Idade,
que utiliza estrutura Pessoa como parâmetro inclusive,
lá num Pessoa.h por exemplo,
ou até, com um pouquinho de astúcia, num Pessoa.h e num respectivo Pessoa.c,
conforme vocês já devem ter visto isso em disciplina precedente.
Mas, enfim, você pode configurar, nesse momento, da maneira que melhor lhe convier.
Aqui, pra atender aos requisitos,
nós mudamos, ou melhoramos, a função Calc_Idade.
Agora, em vez de dois parâmetros, ela tem 4.
O primeiro parâmetro continua sendo o p do tipo estrutura Pessoa.
E, aqui, os parâmetros subsequentes agora não são um, mas três:
dia, mes e ano, todos inteiros.
Eu continuo tendo uma variavelzinha temporária, ali, idd do tipo inteiro.
Aonde eu faço ano - p.ano.
Agora eu faço um teste,
eu vejo se o mês da pessoa que tá sendo tratada é maior que o mês atual.
Por exemplo, se o mês aqui for 10, outubro, e o mês atual for julho
aí, obviamente, que eu vou ter que descontar um ano
porque a pessoa não fez aniversário ainda.
Se esse if não passar, cai num else
Nesse else, eu tenho um outro if aninhado aqui
que eu testo se não está no mês do aniversário.
Se tiver no mês de aniversário, por exemplo, imagine que
o mês da pessoa é outubro e o mês passado por parâmetro é outubro também.
Mas, por exemplo, o dia que a pessoa nasceu é dia 3,
e ali, por exemplo, o dia aqui passado, por parâmetro, seria 1.
3 é maior que 1? É.
Significa que, muito embora, esteja no mês de nascimento da pessoa
a pessoa ainda não fez aniversário e descontaria também
aqui um ano porque não completou a data certa
pra contabilizar aquele ano, né, de idade.
Bom, isso aqui é uma lógica bastante simples, tá.
Até permite a gente revisar um pouquinho de linguagem C, obviamente.
Mas, basicamente, o que você fez aqui foi um cálculo mais refinado
do cálculo idade de Pessoa.
E é retornado aqui o idd.
Se eventualmente, insisto,
Não é porque a pessoa não fez... Não tá no mês de aniversário ainda.
Ou não tá no dia de aniversário ainda, mesmo que esteja no mês
É descontado um ano aqui, porque... Pro cálculo não dar errado, não dar impreciso.
Ok.
E a função main mudou pouca coisa, o que muda, muito que naturalmente,
é que agora o Calc_Idade, em vez de receber
apenas a estrutura Pessoa pertinente, no caso, né, aqui a
Einstein na primeira chamada e Newton na segunda chamada,
ela recebe também, além do ano, um suposto dia atual e mês atual.
E aqui, acontece, daí, o cálculo normalmente, depois é
imprimido através do printf e usando aqui as astúcias usuais desse comando.
Aqui uma observação com relação ao getchar() que serve pra segurar a tela.
Dependendo do ambiente de programação que você estiver utilizando,
pode ser que a tela não fique segura, né, ou seja, você executou o programa
e ela fecha sozinha e não dá tempo de você ver as mensagens aqui, tá.
Então, isso daqui é um getchar() pra que se o ambiente, eventualmente, não...
Não segurar a janela pra você poder ver
o que foi calculado aqui, enfim, a informação posta,
o getchar() espera você apertar um caractere,
enfim, apertar alguma tecla, pra depois ele continuar
na execução do programa que por prioridade eu tô chamando o return 0.
Bom, essa foi uma primeira versão do programa, então.
Se você olhar o programa pra frente,
aliás, se você olhar a próxima versão, o que ocorre lá?
Bom, teve uma pequena mudança, tá, nessa versão 2.
Tanto que eu continuo chamando de 2, tá, porque a mudança vai ser tão pequena,
ela é relativo a isso aqui ó.
Aqui é int idd.
Agora no próximo slide, slide 7.
Vocês vejam que eu não tô mais criando a variável temporária.
Não faz sentido, porque eu não preciso dessa variável temporária.
O próprio p já tem um campo idade.
Então eu posso usar esse próprio campo idade que vem com o p,
pra fazer o cálculo evitando o tempo gasto com uma variável a mais.
Então agora o p.idade que recebe o cálculo idade,
e aqui o próprio p.idade que vai ser decrementado, se for o caso.
Depois eu retorno p.idade.
Aqui eu tomei um outro cuidado também,
que não havia sido tomado na versão anterior, aliás, no momento anterior,
que é o campo idade ser inicializado com -1.
variáveis elas sempre tem que ser inicializadas, esse é um mantra da programação.
O deixar de inicializar variáveis, mesmo numa situação simplória como essa,
por incrível que pareça ela pode acarretar numa série de erros.
então, pra evitar problemas
e mesmo, evitar uma longa discussão aqui no nosso vídeo, acreditem em mim.
Se existe variável, ela tem que ser inicializada.
Esse é o mantra.
Eu imagino que vocês já tiveram a oportunidade de discutir
isso nas disciplinas passadas, aí, de programação, tá.
Se não tiveram, estão tendo agora.
Existe variável, ela tem que ser inicializada
Aqui a variável idade que pertence a Einstein, é inicializada com -1,
idade que pertence a Newton inicializada com -1.
Mesmo que fique logo em seguida,
idade de Einstein e Newton vão ser calculadas.
E aqui eu imprimo, naturalmente, os cálculos feitos.
Agora eu vou passar pra uma versão 2', certo.
Vamos ver o que vai mudar nessa versão 2'.
Saliente, antes de mudar pra versão 2',
aqui na versão 2 ela mesma, que o Calc_Idade
é uma função que retorna inteiro,
tanto é que eu tenho aqui o retorno p.idade.
Certo.
Agora sim a versão 2' no próximo slide, slide 8.
Vejam que a função modificou aqui,
ela passa pra um retorno void, ou seja, um retorno vazio,
na prática ela não retorna nada.
Tanto é que eu chamo aqui a função Calc_Idade,
sem jogar o valor que tá sendo calculado pra algum lugar,
porque, justamente, o Calc_Idade não traz retorno.
O que eu faço aqui é passar,
no caso da primeira chamada de Calc_Idade, destacado em vermelho,
o Einstein, a variável Einstein, que é uma variável composta, por quatro campos,
e a suposta data atual,
aqui dia atual, mês atual e ano atual.
Aí eu faço coisa similar na segunda chamada,
obviamente na segunda chamada eu passo Ein... Eu passo Newton, perdão.
A questão que se impõe aqui é a seguinte, funciona esse programa?
Bom, ele compila e ele roda.
Agora, ele não funciona corretamente ainda.
Do segundo que a gente esperaria que ele funcionasse, porque ele não vai fazer o cálculo
O que vai acontecer aqui, ele vai imprimir aqui, ó, -1,
e aqui ele vai imprimir -1 também.
E por que isso se dá assim?
Ora, aqui eu passo Einstein pra função,
então aqui o p da primeira chamada,
vai ser equivalente a Einstein
só que o que acontece com o p aqui dentro da minha função, não altera Einstein.
Por quê? Porque é uma passagem de parâmetro por valor,
e essa é a natureza da passagem de parâmetro por valor.
Agora a gente pode ter um olhar mais técnico, tá.
Ali, na prática, a hora que eu passo,
pro Calc_Idade o Einstein, eu tô fazendo p receber Einstein,
e, nesse caso, o p é uma cópia de Einstein,
em sendo uma cópia local,
o que acontece com essa cópia não afeta
quem tá doando o valor lá que é o Einstein,
então, tecnicamente falando é uma cópia.
Se eu alterar aqui, coisa que acontece,
o valor de p.idade, ou seja, o campo idade de p,
como p é uma cópia, insisto,
isso não vai alterar Einstein, tal qual não altera Newton na próxima chamada, né.
Então, muito cuidado com essa questão de passagem de parâmetro por valor.
Isso serve como uma pequena revisão da disciplina anterior, tá,
lembrando aí pra vocês a diferença entre a passagem de parâmetro por valor e por referência.