A próxima versão do programa que não vai ser mais 2'
e, sim, versão 3, do grupo de slide 9,
a gente já muda de situação.
Aqui o p não é mais uma cópia do que vem por parâmetro,
O p é um apontamento do que vem por parâmetro.
Dito em mais alto nível, o p é uma passagem de parâmetro por referência.
Então, o p dito de maneira, talvez, quase pré-escolar
é um apelido de Einstein dentro da função.
Quando uma passagem de parâmetro é por referência
é necessário colocar o asterisco aqui na frente de p,
e na chamada da função é necessário colocar o & na frente da variável.
Eu marquei isso aqui ainda, uma...
O parâmetro aqui no caso é uma estrutura, né.
A variável é a partir de uma estrutura, ou seja, é uma variável composta,
eu tenho que usar aqui o operador de seta.
Aqui, no caso, eu tô falando do campo idade do cara apontado por p.
Quem que é o cara apontado por p?
É o Einstein.
Aqui eu tô pegando o campo ano,
do cara apontado, apelidado, por p.
Quem que está apelidado de p nesse contexto?
É o Einstein.
Bom, acho que foi uma explicação, talvez, bem alto nível,
mas vocês que já fizeram
a linguagem C no passado vocês sabem que, na verdade,
esse asterisco p significa um ponteiro.
Então, aqui, na verdade
eu até já tava fazendo esse meu discurso quase intuitivamente
que idade... Que o campo idade do cara apontado
pelo ponteiro p.
Quem que é o cara apontado por p nesse momento?
Nesse momento, o cara apontado por p é o Einstein.
E pra um ponteiro p, aqui no caso,
aponta para uma variável eu preciso passar o endereço dessa variável.
por isso do & aqui.
Agora que eu tô trabalhando com ponteiro,
e a gente sabe que o ponteiro, na verdade, é apenas um...
Um nome alternativo, por assim dizer, pra variável dada,
ou seja, continua sendo o mesmo elemento no final das contas
via um ponteiro, bem entendido.
O que acontece aqui dentro
com o campo idade do cara apontado por p, afeta sim quem doou o valor.
E, nesse caso, na primeira chamada Einstein vai ser alterado,
e na segunda chamada, Newton vai ser alterado.
Portanto aqui, no campo idade... Na impressão do campo idade de Einstein
e depois na impressão do campo idade de Newton,
obviamente, que vai aparecer o valor calculado
em cada chamada, respectiva, do Calc_Idade.
Então, bastante atenção com isso.
Em linguagem C, além de poder utilizar,
no caso de apontamentos de estrutura, esse operador de seta,
pra acessar os campos do cara apontado,
que, por exemplo, eu tô acessando lá, na primeira chamada da função
eu tô acessando o campo idade do Einstein
através do operador de seta.
Existe uma outra possibilidade sintática, que é equivalente, tá.
Que, muito embora, seja menos usual, industrialmente
ao melhor do meu saber, na prática, ela também funciona.
Ela é prevista na gramática da linguagem C.
Então, eu vou mostrar pra vocês isso agora, na versão 3B.
Prestem atenção aqui que vai mudar esse operador de seta.
Equivalente ao operador de seta, é utilizar
os parêntesis, um ponto e mais um asterisco na frente do p.
Vocês sabem que se fosse na... Uma variável normal,
eu poderia colocar o asterisco na frente do ponteiro dessa variável...
Bom, retificando meu discurso.
Se eu tenho um ponteiro x,
que aponta pra uma variável dada,
pra acessar o valor
da variável dada, através de x, eu coloco *x.
Aqui eu quero acessar, então, os valores da variável p.
Tá aí o *p.
Mas como é uma estrutura, uma coisa composta
eu tenho que usar aqui esses parêntesis pra denotar que é uma estrutura composta.
E colocar o ponto, aqui, pra acessar o campo idade.
Novamente, tá, essa aqui é uma sintaxe um pouquinho mais complicada,
mas ela é equivalente, tecnicamente falando,
e execucionalmente falando,
é equivalente a essa que eu tava mostrando anterior,
vou voltar um pouquinho ali, ó.
Então, esse 3 e esse 3B (versão).
Eu prefiro, naturalmente, utilizar essa sintaxe de seta
porque me parece muito mais intuitiva,
que essa aí de asterisco, parêntesis e ponto.
Mas ambas funcionam, insisto.
Em linguagem C,
você, usualmente, tem duas formas de passar parâmetro,
por valor e por referência,
sendo que referência você vai usar ponteiro.
Na linguagem C++,
passagem de parâmetro por valor você faz da mesma forma
que você faz em C, que é lá, a cópia de valores,
e já passagem de parâmetro por referência, em C++, bem entendido, C++,
você tem duas maneiras de se fazer:
um se faz tal qual na linguagem C, que é assim que vocês tão vendo em tela, usando ponteiro,
seja com sintaxe de seta, seja com, sei lá, outra sintaxe alternativa, você usa ponteiro.
Além de usar ponteiro, você pode usar, daí, a segunda maneira de fazer a coisa em C++,
que é a chamada referência escondida.
Então, agora, eu vou mostrar uma versão 3C, desse programa aqui,
e aí, esse programa de agora já não está mais em C.
A próxima versão do programa não compila em C, só compila em C++, bem entendido.
Olhem aí.
Agora já é um programa em C++.
Lembrem-se que o C++, ele comporta também
a programação procedimental, que é o caso aqui.
Esse é um programa feito em paradigma procedimental.
Se você olhar aqui, agora,
tem essa possibilidade da referência escondida.
A referência escondida se dá, em C++, colocando um &
na definição da função
no parâmetro que você quer que seja por referência.
Aqui eu tenho Calc_Idade, Calc_Idade tem como parâmetro por referência o p,
por isso que eu coloquei um & aqui.
Quando é referência escondida, pra você acessar o campo do cara referenciado
você usa, simplesmente, o operador de ponto, p.idade.
Aqui eu vou acessar o campo idade do cara referenciado por p.
Professor, mas como é que eu sei que é mesmo uma passagem de parâmetro por referência aqui?
Por causa do comercial lá.
Já na chamada, simplesmente, passa o nome da variável.
Isso é diferente de ponteiro que é explícito.
Aqui você coloca só o & na definição.
E aí, você passa aqui a variável que você quer que seja tratada por referência, tá.
Aqui ele vai sim, fazer um cálculo lá dentro
e o que acontecer lá dentro com o p vai alterar o Einstein.
Aqui, por exemplo, no p, na segunda chamada do Calc_Idade,
vai alterar o valor do campo idade de p.
O que vai alterar, por consequência, o campo idade do Einstein,
imprimindo aqui, o valor calculado.
Novamente, no C++ você pode usar
pra passagem de parâmetro por referência
o ponteiro normal, tal qual você fazia em C,
ou você pode fazer a referência escondida que é essa exposta em tela.
Qual é a vantagem da referência escondida?
Ele fica um código mais limpo,
basta você colocar o & na definição do parâmetro que será por referência na função.
Você volta a utilizar o operador de ponto aqui, tranquilamente.
Na chamada, basta passar o nome da variável.
É essa a vantagem, querendo ou não, a programação é mais limpa.
A desvantagem, é que olhando a chamada da função,
você não sabe mais, em C++, só olhando ela aqui,
se ele é por referência ou se ele é por valor.
Você tem que olhar a função pela assinatura da função,
pra saber o que tá acontecendo.
Aqui eu só sei, nesse programa,
que essa passagem de parâmetro é por referência,
porque eu olho aqui, na função,
na definição da função e vejo que tem um & ali.
Vocês podem usar a maneira que vocês acharem mais apropriado,
mas tem que tomar esse cuidado, tá,
que olhando só a chamada da função agora,
a passagem de parâmetro por referência, insisto,
você não sabe mais se é por valor ou por referência,
você tem que ir lá pesquisar a função e lá é mesmo.
Muito bem. Isso considerado,
aqui a gente já está em um programa C++, né,
porque você tá usando referência escondida que só tem em C++,
tal qual eu destaquei aqui no slide,
mas lembrem bem que isso aqui, ainda, é um programa procedimental,
ele não tem nada, por ora,
de algo que, à primeira vista, lembre um programa orientado a objetos.
Muito embora, esteja muito bem estruturado,
tem aqui a estrutura Pessoa, tá aqui o Calc_Idade que trabalha com Pessoa,
pra direita tem o main aqui.
Ele tá organizado, mas ele não tá usando os recursos explicitamente da orientação a objetos,
que acontece no próximo slide, que é o slide 12.
No slide 12 a gente começa a ter ares da orientação a objetos.
Deixa eu voltar no 11 aqui ainda e fazer uma lembrança.
No 11, veja que a estrutura pessoa começa e termina aqui.
Depois tem esse ponto e vírgula.
Esse ponto e vírgula aqui ele é um gerador de sabores
de dificuldades, tá, muita gente esquece esse ponto e vírgula aqui
e se bate um monte depois, porque não sabe onde que tá dando erro
Então, lembrem-se, tá, depois de uma estrutura tem que ter um ponto e vírgula,
ele tem que ser sempre lembrado com veemência.
Ele tem que existir depois da estrutura, fechando a estrutura.
Então, vejam que nesse programa aqui, procedimental,
a estrutura termina aqui.
Depois que define o campo idade ele vem e termina
a estrutura com ponto... Chaves de finalização e põe o ponto e vírgula ali.
No slide número 12, você vê uma forte diferença,
agora a estrutura termina lá em baixo.
Vejam o ponto e vírgula lá.
Isso significa que a estrutura agora, além de comportar
os dados, os campos aqui ela comporta também a função.
Como é que é, professor, então, a estrutura além de ter dados, ela tem a função?
Sim.
A estrutura, agora, já num programa mais C++
indo pra direção da orientação a objetos,
as entidades além de ter dados, elas têm, também, capacidades.
Por quê? Porque se você pegar um objeto do mundo real,
uma pessoa do mundo real, ela tem uma idade
e ela também é capaz de calcular sua própria idade
eu, por exemplo, se, eventualmente, esquecer a idade que eu tenho
eu posso pegar o ano que eu nasci, posso pegar o ano atual e calcular
eu consigo fazer isso, não é isso?
Então essa capacidade de cálculo tá no objeto pessoa no mundo real,
então aqui ela também tá na própria pessoa.
Se você olhar agora Einstein e Newton,
são módulos, ou objetos, do tipo pessoa
não são mais apenas variáveis agora,
por quê que são módulos e não são mais apenas variáveis?
Porque agora Einstein e Newton tem capacidade de cálculo, eles conseguem fazer algo.
Então tá aqui o Einstein e o Newton que são do tipo estrutura Pessoa.
Eu inicializo os campos diaP, mesP e anoP de Einstein,
que estão definidos aqui.
Mudou, inclusive, antes era apenas dia,
agora eu resolvi chamar de diaP, mesP e anoP por algum motivo.
Talvez por que seja o dia da pessoa, o mês da pessoa e o ano da pessoa,
deixar um pouco mais explícito isso, mas tudo bem.
Aqui eu poderia, e deveria, ter Einstein.idadeP recebendo -1.
deixo vocês atualizarem isso.
Aqui eu amarro e inicializo os dados do Newton, os campos do Newton.
E vejam que interessante agora.
Agora o Calc_Idade ele não recebe mais o Einstein por parâmetro
O Einstein tem o Calc_Idade, olha o operador de ponto ali.
O Einstein.Calc_Idade();
Aí, simplesmente, eu passo pro Calc_Idade do Einstein,
o suposto dia atual, mês atual e ano atual.
supostos né, dia atual, mês atual e ano atual.
o que eu coloco aqui também, na chamada relativa a Newton.
Então, o Einstein tem o seu Calc_Idade e o Newton tem o seu Calc_Idade por assim dizer.
E depois o Einstein informa a sua idade aqui, e o Newton também, né
animados, estimulados pelo printf.
Isso aqui é um salto grande, tá, é um salto grande, porque agora
você tem um único local
pra um dado tipo que tem os dados daquela coisa
e as funcionalidades daquela coisa.
Aqui, o exemplo ainda que simplório, você já percebe isso.
Einstein tem os seus dados e a sua função de cálculo, idem pro Newton.
Muito bem.
Isso considerado, agora a gente vai fazer uma evolução desse programa uma vez mais.
Vou passar do slide 12 para o 13.
O 13 tem um avanço aqui.
Eu criei mais uma função.
É uma função bastante peculiar, chamada função construtora.
A função construtora ela tem o mesmo nome da estrutura Pessoa.
Então, tá aqui a estrutura Pessoa.
Tá aqui os campos: diaP, mesP e idadeP.
Aqui, não estava explícito antes, mas, agora, acho que eu estou explicitando nessa versão,
que essas informações são públicas, ou seja, elas são acessíveis de fora,
tanto elas são acessíveis de fora que lá eu consigo acessar,
idadeP de Einstein que é do tipo Pessoa. Muito bem, elas são públicas.
Aqui, além de ter a função Calc_Idade, já definido na versão anterior
e vejam que eu coloquei reticências aqui
apenas pra contar que o código está ali, mas eu não estou mostrando
pra deixar mais fácil minha explicação nesse momento.
Inclusive, já vários ambientes de desenvolvimento utilizam esses três pontos aqui
se você quiser esconder, por ora, o código que tá ali dentro.
Bom, está aqui, enfim, a função Calc_Idade.
Agora, além da função Calc_Idade, eu tenho essa função peculiar, aqui,
que é a função construtora.
A função construtora ela tem, impressionantemente, o mesmo nome da estrutura,
então, é Pessoa.
E aqui eu tenho os parâmetros:
dia de nascimento, inteiro, mês de nascimento, inteiro e o ano de nascimento inteiro.
Esse parâmetro aqui recebido nessa função, diaNa vai alimentar o diaP,
mesNa vai alimentar o diaP (mesP) e o anoNa vai alimentar o anoP.
E aqui, o idadeP que não tem parâmetro que o alimente,
isso porque o idadeP vai ser fruto de cálculo depois,
eu inicializo, por ora, o idadeP com -1.
Lembrando, toda variável tem que ser inicializada, isso é mântrico.
Legal.
Agora no outro lado aqui desse slide, na função main.
Você tem o Einstein e o Newton,
quando você definiu uma construtora numa estrutura,
você cria um módulo, a partir dessa estrutura, em C++
como aqui o Einstein que é um módulo, ou objeto, do tipo, ou da classe, Pessoa.
Einstein do tipo Pessoa.
Como você definiu na construtora que ele tem esses três parâmetros
você já passa esses três parâmetros aqui, mesma coisa com o Newton.
E é assim que faz, a sintaxe é um pouquinho peculiar, eu sei, mas é assim que faz.
Depois o que você faz, chama o Calc_Idade do Einstein
chama o Calc_Idade do Newton e imprime a idadeP.
Eu vou mostrar agora uma outra sintaxe, que poderia ter sido uma sintaxe razoável,
mas não foi por esse caminho que o Stroustrup elaborou o C++, tá.
Ele poderia ter feito assim, mas ele não fez.
A sintaxe seria assim.
Muita gente tenta fazer isso, inclusive, mas dá erro.
Na maior parte dos compiladores, pelo menos, dá erro.
Talvez algum ou outro compilador que não respeite tanto a gramática
de maneira tão observadora,
a gramática do C++, talvez passe,
mas, via de regra, não deveria passar.
Então isso aqui vai, normalmente, gerar erro.
Em vez de fazer assim, eu volto um slide, volto pro 13, você tem que fazer assado.
Muito bem.
Qual é a vantagem, então, de utilizar uma construtora?
A vantagem de utilizar um construtora, gente, é que o código fica mais limpo.
Você cria aqui o teu módulozinho aqui,
a instância do teu módulo, né, Einstein do tipo pessoa
e você já põe os valores que inicializam nele.
Aqui, 14, 13 e 1879.
E ele vai usar esses valores aqui, apropriadamente, pra inicializar
cada elemento apropriadamente
e o que não tiver valor pra alimentar o campo
lá dentro do objeto, do módulozinho, você coloca algum valor
que seja razoável, aqui, por exemplo, pro idadeP -1.
O -1 é uma codificação dizendo
que claro essa idade não tá ainda calculada, ela precisa ser calculada em algum momento.
Momento esse que acontece aqui depois.
Com o Newton coisa parecida.
O Newton usa a construtora e depois calcula a idade.
Muito bem.
No slide aqui, estamos no slide 13, aqui no 14 essa solução que a gente sabe que tá errada, né.
E agora a gente passa pro slide 15.