Reflexão sobre a função Calc_Idade()
no quesito desacoplamento, inclusive, no código de vocês
eu gostaria que vocês já fizessem
de maneira desacoplada,
tal qual, no exemplo que a gente viu agora pouco ali na prática
Passamos a uma segunda reflexão, que é essa posta aqui.
Quando se programa em C++, deve-se fazê-lo
o mais orientado a objetos possível
supondo que você é um porrista da orientação a objetos
ou que você prefere fazer as coisas orientada a objetos.
Nesse sentido, em orientação a objetos,
o programa deveria começar já a partir de um objeto
de uma classe tida como principal.
Entretanto, nos exemplos mostrados até então
começam a partir de uma função, procedimental, que é a função main.
Na verdade, o C++ nos obriga a começar a partir da função main, via de regra,
ou uma função equivalente a main, né,
conforme o ambiente, como a _tmain.
lá no Microsoft.
Assim sendo, como resolver este impasse
esta, entre aspas, "deficiência" do C++?
Vamos resolver essa reflexão já propondo um exercício.
Se vocês quiserem vocês podem tentar fazer esse exercício
é um desafio, inclusive,
porque vai exigir uma série de reflexões de vocês, tá.
Ou vocês podem, de maneira mais confortável,
escutarem agora aqui a leitura do exercício, dos requisitos do exercício,
olharem a solução que eu vou propor, ato contínuo,
e depois tentarem voltar a resolver o exercício
por vocês mesmos já tendo visto uma resolução minha.
Exercício número um aí, propõe o seguinte:
criar uma classe principal, na qual,
cada objeto que venha a existir no sistema,
por exemplo, objetos da classe Pessoa.
sejam criados ou instanciados.
Assim, a função main deverá instanciar somente um objeto da classe principal,
respeitando uma boa conduta
de elaboração de sistemas orientados a objetos.
Então, isso significa o quê?
Significa que eu não vou ter mais, na minha main,
toda a criação de um conjunto de objetos
eu vou criar apenas um objeto que é da classe principal.
A classe principal, por sua vez, vai ser a classe do sistema,
se a gente quiser colocar assim,
que vai criar os demais objetos,''
que ela vai animar, que ela vai tratar.
Ainda tem uma observação ali, tá.
Pra tratar entrada e saída, utilizar cin e cout.
Pra se acostumar com esses comandos que são típicos do C++, tá.
Bem entendido, que o printf e o scanf também funcionam em C++.
O C++ dá suporte a esses comandos,
mas ele tem essas versões mais
modernas, por assim dizer, que é o cin e o cout.
Bom, antes de criar a classe principal,
eu vou fazer uma pequena modificação
na classe Pessoa, porque isso me é importante
no contexto que eu vou trabalhar.
Eu estou criando
duas funções a mais
dentro da minha classe Pessoa.
A primeira função, é uma outra construtora.
Professor, mas o senhor já tem um função Pessoa,
como é que pode ter outra?
Você pode ter outra se
os parâmetros forem diferentes e não conflitantes
com o que já tinha.
Aqui, por exemplo, eu tenho
de três a quatro parâmetros, eu tenho valor default,
e nessa outra versão aqui,
eu não tenho parâmetro nenhum.
Então, o compilador permite.
Eu poderia, por exemplo, ter um outro Calc_Idade aqui
com um parâmetro só, relativo ao ano.
Cálculo de idade mais cru, menos refinado
que esse que leva em consideração o dia e mês.
Eu poderia ter aqui só um: void Calc_Idade (int anoNT);
E aí, como é que eu ia diferenciar na chamada? Em função da parametragem.
Se eu passava um parâmetro ele executaria
o suposto segundo Calc_Idade que eu teria aqui.
Se fosse três parâmetros ele ia executar o que está aqui.
Se fosse algo diferente de um ou dois parâmetros, ele daria erro.
Além de tudo, eu criei uma nova função inicializar aqui.
Opa, perdão, inicializa.
Não tem o 'r' é inicializa.
que tem quatro parâmetros, similar ao... aliás,
equivalente aos parâmetros que eu tenho na construtora, veja lá.
diaNa, mesNa, anoNa, todos inteiros.
e o nome que é um ponteiro de caractere
pra lidar com vetor de caracteres no fim das contas
que tem valor default abre e fecha aspas aqui.
Se você olhar, agora aqui, a construtora,
em vez de ela fazer os casamentos
eu passar os parâmetros que estão aqui, para os atributos, né,
ela não tá fazendo isso, ela tá repassando para uma função inicializa().
Tá vendo, ó, diaNa, mesNa, anoNa e nome
estão sendo passados pra função inicializa()
e essa, por sua vez, que faz aqui
o casamento entre os parâmetros e os atributos
Bom, o nome alimentando o nomeP ali, a título de exemplo.
Se você olhar a construtora sem parâmetros,
a construtora sem parâmetros também chama inicializa(),
só que zerando tudo.
Na construtora sem parâmetros então,
ela é criada pra zerar todos os atributos.
Nesse caso aqui, eu tô usando como artifício
uma chamada da função inicializa
inclusive, não passo o quarto parâmetro, porque ele já é
um zeramento em alguma medida, tá.
Obviamente que eu podia ter esse código aqui.
O que tá aqui, ali.
E aqui podia fazer na unha,
diaP = 0, mesP = 0, etc e tal.
Só que inicializa() aqui, é uma maneira de organizar, não deixar códigos
com alguma repetição, ali, nas minhas construtoras.
Pessoal, em C++, ele tem uma peculiaridade
de sempre ter uma construtora sem parâmetros.
Se você não criar essa construtora sem parâmetros aqui pra ele,
igual eu fiz aqui,
ele cria pra você e você não vê esse código.
O C++ faz isso, tá.
Ele cria a construtora sem parâmetros, porque ele precisa disso
em certas situações
e na melhor das hipóteses
essa construtora sem parâmetros vai ser algo
como se fosse, isso aqui vazio, tá.
Sem nada aqui, só um abre e fecha chaves aqui.
Bom, as boas práticas de C++ diz o seguinte:
crie, você mesmo, a sua construtora sem parâmetros
e tenha controle do que tá lá.
Que é o caso aqui.
Nós criamos nossa construtora,
e nós temos controle
mas vejam que é um controle importante.
a gente tá garantindo que todos os atributos
estão sendo inicializados com 0.
Se você tem alguma situação, via construtora,
no qual os seus parâmetros não são inicializados
inclusive, numa situação dessa,
da construtora ser criada automaticamente pelo C++
com abre e fecha chaves
sem inicializar atributo algum,
isso é uma fonte de erros tremenda.
Então, insisto, crie a sua construtora sem parâmetro
ou equivalente, depois a gente vai discutir o que é equivalente,
de maneira tal que essa construtora sem parâmetros
zere, em alguma medida aí, os seus atributos.
Bom, então eu fiz essa mudança aqui
criei uma construtora a mais, criei o inicializa()
agora a construtora que já tinha chama o inicializa passando a parametragem correta.
e a nova construtora sem parâmetros
chama a inicializa passando a parametragem correta, tal qual.
Aquele inicializa aqui, já foi visto.
Reticências vai aparecer o que aqui?
Eu sei lá, o Calc_Idade(), informaIdade()
tão aí pra baixo, tá, supostamente.
Muito bem, isso dito, avancemos aqui agora
pra nossa classe principal.
Tá aqui a nossa classe Principal.
Ela é uma classe, portanto, ela tem que ter um nome.
Ela tem um abre e fecha chaves, olha o ponto e vírgula.
Ela tem uma parte privada que é a parte
das variáveis dela, por assim dizer, atributos dela, né.
E ela tem uma parte dos métodos das funções membro.
As funções membro.
Se você olhar aqui, os atributos
é peculiar, porque agora eles não são mais de tipos pré-existentes, né.
Tipo inteiro, float
char, vetor de char e afins.
Agora eu já tô criando como atributo, objetos aqui ou
estou criando atributos que são, na verdade,
objetos de tipo que eu criei.
O Simão, o Einstein e o Newton são da classe Pessoa
e a classe Pessoa foi eu, ou fomos nós, que criamos aqui.
Então, tem essa peculiaridade agora.
Ali na construtora Principal, eu estou chamando o inicializa
do Simao, do Einstein e Newton, tô passando valores aqui.
O Simao, por exemplo, dia, mês e ano de nascimento
e aí um nome pra ele.
Coisa similar acontece com o Einstein e o Isaac Newton.
O que diferencia são os valores passados, obviamente.
No executar, eu vou chamar o Calc_Idade()
do Simao, do Einstein e do Newton
passando aqui a suposta data atual.
Poderia, tranquilamente,
criar artifícios pra perguntar pro usuário
o dia, mês e ano atual
ou recuperar isso do sistema.
Se você olhar a main agora, a main tá ficando mais enxuta,
ficando mais orientada a objetos.
eu tenho o objetoPrincipal,
podia chamar isso tudo aqui de sistema, inclusive, tá.
Em vez de chamar objetoPrincipal, podia chamar de sistema,
mas, enfim, o objetoPrincipal da classe Principal.
objetoPrincipal.Executar();
O que o objetoPrincipal vai fazer?
Vai inicializar
vai criar, inicializar esses caras aqui
e a execução
vai executar esses caras aqui.
E agora meu main ficou mais limpo, tá, insisto.
Também posso melhorar sempre o código, tá.
No próximo slide,
tá aí uma melhora
em vez de chamar o Executar() ali
eu chamo direto aqui.
Assim eu crio o objeto
ele vai inicializar as coisas e depois ele chama o executar.
Bom, mas vamos melhorar mais ainda esse código.
Aqui, em vez de chamar isso aqui V1
devia se chamar V1', tá.
Voltei uns slides ali pra fazer essa observação, bem entendido.
Aqui vocês observem que sempre tem a página dos slides, tá,
pra vocês saberem quando eu tô indo, ou voltando.
Agora indo pra versão 2,
já no slide 20,
que é o seguinte.
Aqui eu não tô fixando uma data, né, na execução.
Eu criei mais três atributos pra classe Principal:
diaAtual, mesAtual e anoAtual.
Leio isso, através do cin da construtora.
Como os métodos de uma classe
e, portanto, de cada objeto subsequente
eles... os métodos compartilham acesso aos atributos
eu li o diaAtual, mesAtual e anoAtual aqui,
e reutilizo lá.
Então, esses atributos eles são acessíveis,
em qualquer uma das funções da classe em questão,
assim, o objeto principal, a hora que eu criar...
vejam que aqui eu tenho uma construtora sem parâmetros,
aqui é uma construtora sem parâmetros,
que já atende àquela regra de ter uma construtora sem parâmetros
de eu mesmo ter, tá, aqui minha construtora sem parâmetros.
Alguns compiladores, quando tem uma construtora sem parâmetro,
eles não permitem eu chamar assim sem... sem parâmetros.
Eles querem que eu chame, apagando isso aqui
colocar só o "objetoPrincipal;".
Depende um pouquinho o compilador.
Hoje, os compiladores mais modernos, via de regra, não gostam disso aqui,
isso aqui tá nos slides, inclusive, pra lembrar
que alguns compiladores antigos aceitavam,
os mais modernos, via de regra, já não aceitam isso aqui, tá.
Então, você escreveria apagando isso aqui,
mas, enfim, vocês façam o teste,
só que tem essa observação, porque isso aqui é importante, tá.
Se isso aqui der erro na compilação, você tira esse
abre e fecha parêntesis aqui
põe só "objetoPrincipal;", executa e ele deve funcionar.
Legal.
Falando em funcionar,
aqui tá a execução, inclusive,
feita outrora.
Muito bem.
Aqui eu tenho uma versão com o time.h
aparentemente eu não mostrei todos os códigos não sei porquê motivo,
mas tem o time.h.
Em vez de eu perguntar pro usuário
o dia, mês e ano atual
eu tô calculando através de artifícios do time.h.
Outra maneira de utilizar também é o Windows.h
se você estiver trabalhando no Windows, tá.
Ele tem lá uma estrutura chamada SYSTEMTIME.
Eu tenho a função GetSystemTime()
que eu passo aqui a estrutura que eu criei st,
por referência inclusive.
Ele vai retornar, a partir do sistema operacional a data atual.
Eu consigo, dentre outros,
recuperar o dia, o mês e o ano.
Olha aqui, ó: st.wDay;
st.wMonth;
st.wYear;
Recupero ali e depois utilizo acolá.