Pessoal, boa noite.
Hoje é o dia 7 de julho de 2020.
Estamos nós aqui no
Grupo de Slides número 2,
intitulado: Relações entre objetos em C++.
Aonde a gente começa a entrar nessa temática
que é tão rica.
Bom, aqui a gente tem o cenário
que nós paramos na aula referente ao
Grupo de Slides 1 parte B.
Se vocês olharem aí, vocês têm a classe Pessoa,
com os atributos da classe
e os métodos da classe, as funções-membro.
Não sei se vocês lembram que, a classe ela pode ser
definida no .h
no header, no cabeçalho, e
ser implementada, no tocante aos seus métodos,
no respectivo .cpp.
Aqui nós temos, então, o Pessoa.h e o Pessoa.cpp,
conforme já explicado.
E aqui nós temos a função main.
Nessa função principal é criado os dois objetos de Pessoa,
cito, o Einstein e o Newton,
que recebe aqui inicializações
via suas construtoras
Depois eu chamo o Calc_Idade do Einstein e o Calc_Idade do Newton
passando a suposta data atual.
Por fim, eu tenho aqui a impressão
da idade do Einstein e do Newton
usando dois printf's.
Como idadeP é privado lá na classe Pessoa,
eu não posso vir aqui e colocar direto Einstein.idadeP,
eu preciso de um meio de chegar nessa informação.
O meio que eu tenho é a função pública informaIdade
e ela sendo pública eu consigo chamar de fora
do âmbito do objeto à luz da definição na classe.
Como a função, por sua vez, está dentro do objeto
ela vai conseguir acessar a informação da parte privada.
E aqui eu consigo externar a informação
sem alterá-la, de maneira que...
desavisada no âmbito da main.
Uma outra maneira de alterar,
conforme já foi dito em slides anteriores,
é através do protocolo aqui
de execução ou do rito de execução usando a função Calc_Idade.
Muito bem.
Aí ficou deixado pra vocês esse exercício
que basicamente era encontrar uma maneira
de automatizar esse printf
para que ele acontecesse
o cara printf acontecesse a partir do Einstein e do Newton.
Ou seja, na classe Pessoa, portanto,
eu deveria ter algum automatismo que permitisse
imprimir a idade de cada objeto visado.
Bom, uma maneira de resolver isso, está aqui nesse slide exposto.
Slide número 4, do Grupo de Slides número 2.
Está ali a classe Pessoa. A classe Pessoa tem uma modificação.
Agora ela tem um quinto atributo
que é um vetor de caracteres.
Vetor de caracteres que define em C++, tal qual se define em linguagem C.
Pelo menos esses vetores mais raiz, assim dizendo.
Bom, se eu tenho um novo parâmetro,
esse parâmetro tem que ser...
Perdão. Se eu tenho um novo atributo
esse atributo tem que ser inicializado de alguma forma,
ou através de um valor fixo na construtora
ou senão através de um valor parametral.
É o caso aqui, ó, na construtora de Pessoa
Eu adicionei um quarto parâmetro chamado nome,
que vai alimentar quem? nomeP, por suposto.
Se você olhar lá, você percebe que nome
de fato alimenta nomeP.
Como eu tô usando um vetor de caractere
a gente tá utilizando aqui string.h
e, particularmente, porque eu tô utilizando a função strcpy,
ao bem da verdade.
Essa função aqui que é referente ao string.h no contexto dado.
Vocês sabem, veja lá de fundamentos de programação 1,
que vetor eu não uso o operador de recebe
pra fazer atribuição
eu não posso vir aqui e fazer nomeP recebe nome (nomeP = nome;).
Bom, você não pode, basicamente, pelo seguinte,
porque o nome do vetor, na prática, é um apontamento
é um ponteiro
o nome sozinho de cada vetor, é um apontamento pro início do vetor.
Isso considerado,
isso sabido já de fundamentos de programação 1,
se eu fizer nomeP receber nome,
usar o operador de recebe aqui, eu teria um problema,
porque vocês estaria fazendo um ponteiro, nomeP,
receber um ponteiro temporário, um parâmetro,
ainda sim um ponteiro temporário,
ser recebido lá no nomeP.
Bom, longa história curta,
o fato é que
a gente não faz o operador de recebe em vetores
no C++, salvo se tiver muito controle no que você tá fazendo.
Isso é ainda mais particular pra situação de vetores de caractere.
Assim sendo,
a gente tá usando o comando apropriado aqui que é o strcpy.
Isso vai permitir copiar o que vem lá no quarto parâmetro
para o nomeP.
Observem que, de fato,
aqui a hora que eu crio os objetos, olha lá o Newton.
Além de passar
o dia, o mês e o ano de nascimento
estou passando também agora o nome Isaac Newton.
Aqui, o Einstein, eu passo um quarto parâmetro, Albert Einstein.
Aqui eu criei um objeto a mais a título de exemplo, que foi o objeto Simão.
Coloco ali o dia, mês
e ano de nascimento de Simão e ainda o nome pra ele.
Aqui, depois, por gentileza,
na hora que estiverem fazendo os códigos de vocês,
substituam esse objeto
por um objeto mais na altura do Einstein e Newton.
Quem sabe vocês podem colocar aqui o Galileu, não é isso?
E aí, colocar os dados do Galileu ali
colocando o nome aqui Galileu Galilei.
Aproveitando o ensejo,
vocês devem refazer os códigos de vocês, tá.
Ou, dito de outra forma,
todos esses códigos que eu tô apresentando aqui em sala,
vocês devem replicá-los no ambiente de vocês.
Vocês devem ter um próprio ambiente de experimentação,
aonde vocês vão fazendo as evoluções que eu fiz
aqui nas exposições
e, por que não?
Outras experimentações que vocês queiram fazer e testar,
tá, isso é importante.
Esse sistema vai evoluir aqui,
e cada qual tem que ter a sua versão
desse sistema o seu ambiente de estudo e trabalho
pra ir fazendo a sua base de desenvolvimento
sua base de testes, sua base de experimentação, conforme eu já dizia.
Isso é fundamental.
Isso dito, cada qual, no seu sistema,
vai alterar aqui, então, o nome desse objeto
pra um objeto mais à altura aqui do Einstein e do Newton.
Muito bem, isso considerado,
agora vocês percebem que todos esses parâmetros são inicializados
o primeiro, o segundo, o terceiro, o quarto e o quinto parâmetro.
E por que foi criado esse atributo nome?
Porque eu vou ter que imprimir a idade de cada objeto
e pra eu informar a data
é importante que eu informe o nome também.
Fulano de tal tem tal idade em anos.
E se eu olhar o Calc_Idade aqui e depois fizer o cálculo da idade
eu já estou aproveitando o ensejo e fazendo
a impressão usando um printf aqui.
"A idade da pessoa tal seria tanto".
E aí, eu uso, o valor de nomeP, aqui, como o primeiro parâmetro de informação
e o idadeP como segundo parâmetro de informação.
Se você voltar um pouquinho, alguns slides, aliás um slide.
Você percebe que essa informação vinha incrustada aqui, ó, dentro do printf.
Ó O Einstein teria tanto... O Newton teria tanto...
Agora que eu tô automatizando, generalizando um pouquinho a coisa.
eu criei um escaninho, um atributo, pra armazenar essa informação.
Eu passo a informação na construção do objeto e reutilizo em boa hora.
Certo.
Eu vou fazer algumas versões agora nesse exercício
fazendo algumas variações e, por final...
e, por fim, vou fazer uma consideração um pouco mais profunda com relação
a solução posta aí.
Vamos pro próximo slide e ver o que muda.
Vocês perceberam que aqui, ó,
da definição da função, eu coloquei
que esse parâmetro que é um vetor de caracteres,
vetor de parâmetro.
No fundo, a gente bem sabe que é um ponteiro, tá,
pelas informações que vocês já tem da linguagem C,
mas vamos enxergá-lo por ora em alto nível como um vetor de caracteres.
Eu estou inicializando ele com vazio.
O que isso significa?
Significa que eu posso ter valor default dos meus parâmetros,
visando meus atributos depois, obviamente.
Então, isso significa o seguinte, na chamada da construtora
se, eventualmente, ei ignorar o quarto parâmetro
não vai dar erro, porque ele vai seguir o valor default.
Aqui, por exemplo,
o Simão tem o nome vazio,
podia ter colocado inclusive o valor aqui "fulano", por exemplo.
E daí, na hora de imprimir, ele vai assumir um valor default.
Obviamente que aqui a informação ia ficar meio estranha:
"A idade da Pessoa em vazio seria tanto";
que seria a idade calculada lá pro Simão.
43 anos.
Muito bem.
Então, isso é interessante, tá. Vocês estão percebendo que é possível
ter valores default para os parâmetros
e esse valor default ele é definido na assinatura da função,
não na implementação, só na assinatura.
Legal.
Avancemos um pouquinho.
Eu posso, inclusive,
ter valor default pra mais de um parâmetro.
Aqui, por exemplo,
eu tenho pro anoNA e pro nome.
Tá vendo? Então, eu posso, se eu quiser, ignorar o terceiro e o quarto,
ou senão só o quarto parâmetro.
Então, aqui eu podia ter, por exemplo:
posso ter 3, 10, tranquilamente;
posso ter 3, 10 e 1976, tranquilamente;
e ainda poderia ter 3, 10, 1976 e, ainda, entre aspas "Jean Simão".
Aqui, por exemplo. Aqui eu não ignorei parâmetro nenhum.
Se eu não ignorar parâmetros
aí ele não vai utilizar os parâmetros default,
vai utilizar o que eu defini aqui na chamada.
Só que tem um detalhe com relação a essa questão de...
valores default em parâmetros de função.
Inclusive, valor default pode ter em parâmetros
de construtora ou de método normal.
Inclusive, é possível mesmo, ter em funções procedimental,
mas essa é outra questão.
Vamos nos concentrar na orientação a objetos aqui.
Vamos lá. Imagine que quisesse, por exemplo, colocar aqui o dia
diaAT recebe 0,
e mesAT recebe 0
e não colocar nada no anoAT.
Daria erro, isso não funciona.
Eu posso colocar parâmetros numa...
Perdão, eu posso colocar valor default em um parâmetro
se o parâmetro da direita já tiver valor default,
e o parâmetro da direita ainda tiver valor default.
Então, aqui eu posso, por exemplo, colocar
valor default em mesNA, porque em anoNA tem, e nome tem.
Agora se eu der esse quadro posto, aqui, como está aqui.
Aqui não tem valor default, e eu tentar colocar o valor default aqui, ó,
em diaNa, dá erro,
porque logo o da direita não tem.
Tem que respeitar isso, que é um pouco do que tá dito aqui.
Isso aqui é só um entreposto
pra vocês saberem que é possível ter valores default
em parâmetros de função-membro de classe.
Seja a função ela construtora ou uma função normal como Calc_Idade aqui.
Calc_Idade, nesse exemplo, não tem valor default,
mas ele poderia ter, se assim desejasse e respeitasse as regras colocadas aqui
nesse lado do slide aqui, esse lado direito.
Joia.
Aqui eu voltei um pouco ao quadro que eu já tinha
e mantive o valor default apenas no último parâmetro no nome.
Então, por esse código, que tá exposto nesse momento
eu sou obrigado a, pelo menos, colocar
valor em diaNA, mesNA e anoNA, como eu estou fazendo aqui,
e ademais, estou também colocando o valor no quarto parâmetro
que, eventualmente, poderia ser ignorado, em função do valor default, insisto.
Joia.
Agora aqui eu voltei a colocar um valor fixo.
Eu colocando um valor fixo aqui, colocando "Jean Simão",
obviamente que ele vai ignorar
o valor default, bem entendido.
Legal.
Aqui, uma coisa a ser observada, é que
eu continuo utilizando
esse formato aqui, pro vetor de caracteres parametral,
com char e colchetes, tá,
É uma maneira de mostrar a coisa em bastante alto nível.
Isso considerado, avancemos.
Justamente,
já nessa versão posta aqui, nos nossos slides
eu não tô mais usando o formato do char asterisco...
Perdão, não estou mais usando o formato,
bem entendido, de char colchetes.
Passei, agora sim, usar o char asterisco, ou seja,
passei a explicitar que, na verdade,
o vetor de caracteres passado por parâmetro
é um ponteiro.
Você sabe que todo vetor em C e também em C++,
na prática, ele tem uma relação íntima com
ponteiro, porque o vetor é tratado através de apontamentos.
Inclusive, o nome de cada vetor
é um ponteiro pro início
desse conjunto de dados que é um vetor.
Em termos de memória, bem entendido.
Isso significa, então, que eu posso usar, vou voltar um slide,
ou nesse formato de vetor aqui, em mais alto nível
ou, ser mais sincero, e contar explicitamente
que aqui é um ponteiro.
Inclusive aqui, tá, nada obsta, nada impede
eu ter valor default também.
Eu poderia ter aqui um recebe "abre aspas, fecha aspas".
Poderia tranquilamente e também funcionaria, tá, bem entendido.
Na indústria, pelo menos na luz da minha experiência
tenho nota que o pessoal utiliza mais esse formato
assim de explícito de ponteiro de caractere
quando você vai passar, vai alimentar, um vetor de caracteres com o nomeP.
Até fica mais, daí, entendível,
ou mais bem lembrado,
que eu devo utilizar o strcpy e não fazer o operador de recebimento
com esses ponteiros aí que vocês tão trabalhando.
Muito bem, então, mais uma vez
vetor de caractere quanto parâmetro
não raro, eu vou usar o formato de asterisco char e não de char colchetes.
Legal.
Outra questão, aqui, pertinente
é printf, tá.
O printf é um comando de impressão em tela,
muito usual na linguagem C, vocês estão muito habituados com ele, tá,
mas ele tem algumas peculiaridades, né
porque você é obrigado a informar a tipagem do que você tá imprimindo
Aqui, por exemplo, eu quero imprimir, no âmbito dessa frase,
o nome da pessoa e a idade dela,
pra isso eu me obrigo a saber o tipo do que eu vou imprimir,
%s, ou seja, string, né, um vetor de caracteres
e %d, d vem de inteiro decimal.
E, bom, isso, pra quem tá acostumado
passa batido, mas às vezes pra quem é iniciante
tem um pouco de dificuldade nisso, porque
se a pessoa errar aqui, por exemplo, colocar um %f, colocar um %c
começa a dar erros de impressão
na execução do software, programa,
e a pessoa acha que tem um erro de lógica,
mas, na verdade, não, foi só um erro de
tipo de parâmetro aqui de exposição.
Bom, aí o pessoal resolveu melhorar isso,
mais precisamente, o Stroustrup resolveu melhorar isso,
trazendo um novo comando equivalente ao printf,
mas mais potente e mais alto nível
e, também, gastando um pouquinho a mais de processamento, naturalmente.
Então, no lugar do printf,
você pode usar esse comando de fluxo aqui, tá, que é o cout.
Isso significa, isso você pode encarar como a saída padrão
outramente dito, a tela que é o que tá importando no nosso caso aqui.
Por fluxo, vai acontecer isso aqui, ó,
tudo isso aqui, vai sair em fluxo na tela:
"A idade da pessoa tal seria tanto",
pula linha, esse end line pula linha,
um comandinho end line.
Então você veja que ele fica mais transparente que eu
não preciso contar o tipo de nomeP
nem o tipo de idadeP, eu simplesmente coloco, ele aí nesse fluxo
e a coisa acontece.
O que me leva a ter essa mudança aqui no corpo do meu Calc_Idade
Eu calculo a idade e já aproveito esse ensejo pra imprimir a idade logo em seguida.
E tá... tá legal isso, tá...
bem didático esse comando de cout.
Eu só não contei pra vocês ainda
qual é a biblioteca que eu tenho que utilizar no cout.
lá eu tenho uma reticências, ou seja, código escondido, tá,
e tenho a biblioteca que não vai ser o stdio.
Não é isso?
Deixem isso na manga tá, daqui a pouco a gente vai contar pra vocês
qual é a biblioteca que a gente utiliza aqui pra poder
fazer apelo ao cout, e também ao endl
que são comandos da mesma biblioteca, diga-se de passagem.
Joia.
Próximo slide, que que mudou aqui?
Deixa eu voltar um slide, tá, porque tem uma peculiaridade.
Vejam a função main aqui.
eu crio os três objetos de Pessoa.
Simão, Einstein e Newton.
Aí eu tenho o Calc_Idade de cada um.
Em orientação a objetos a gente tem o costume de criar um
bom nível de encapsulamento.
Bom nível, inclusive, de automatismo.
Será que não tem uma maneira um pouquinho mais automática
de fazer esses cálculos de Calc_Idade aqui sem chamar objeto por objeto?
Tem.
É o que eu faço inclusive no próximo slide.