Vencido essa questão de atributos e métodos estáticos
nós passamos para outro tópico da aula
que é o tópico de namespace ou espaço de nomes
Vocês já repararam que quando você cria, inclui aliás, ou cria inclusões
de bibliotecas de c++
você acaba utilizando essa palavra namespace.
Você quanto está, por exemplo, utilizando o iostream
você faz #include using namespace std;
e esse namespace standard (std)
aparece em várias bibliotecas do c++.
Se fizer #include using namespace std;
#include using namespace std;
O namespace, que no caso do c++ ele já tem um standard,
ele permite agrupar coisas.
Inclusive, o namespace pode estar, eventualmente, em vários .h.
Então o namespace é algo transversal aos .h, aos headers.
Engraçado que no c++ você pode chamar um header de .h ou de .hpp, tanto faz.
Acaba ensinando a gente usar .h por causa da herança da linguagem c, mas emfim.
O fato é que o namespace, o espaço de nomes,
ele pode estar definido em vários .h, significando que ele é transversal aos .h.
É por isso que eu posso escrever , #include , #include , #include
e using namespace std; conforme vocês já viram em outros exemplos nas apresentações anteriores.
Isso tudo disso, o fato é que você pode criar os seus próprios namespace
que são, na verdade, organizadores de coisas.
Isso permite aumentar o nível de coesão e compreensão de coisas.
Aqui eu tenho, por exemplo, MinhasCoisasDeString, namespace que eu criei para a classe MinhaString
que permite eu agrupar, ele começa aqui e fecha ali,
veja que não tem ponto e vírgula, diferente da classe.
Aqui eu coloco o que dentro desse namespace?
Bom, nas minhas opções pedagógicas,
MinhasCoisasDeString tem a própria classe MinhaString e tem o operador de fluxo sobrecarregado
para trabalhar com MinhaSting.
O que eu explica eu ter no espaço de nomes uma classe
e uma função de fluxo,
que é uma função procedimental, por assim dizer, que trabalha com MinhaString.
Então para não deixar as coisas sem um closure, sem um elemento de fechamente,
eu acabei colocando ele no namespace e dando um agrupamento para eles.
Quando você cria um namespace em um .h seu
hora que você vai implementar no seu respectivo .cpp, como é o caso da MinhaString.cpp,
eu coloco #include "MinhaString.h" e using namespace std;.
Significa que você vai implementar o que está escrito na MinhaString.h
particularmente o que está definido dentro desse espaço de nomes.
O resto é normal, continua a implementação normal,
aqui, por exemplo, a função getNomeClasse, conjunto de parâmetros vazio,
getNomeClasse pertence à MinhaString, aqui o retorno, e aqui a implementação.
Então está ai o espaço de nomes para esse caso dado aqui.
Hora que vou utilizar, por exemplo no main, #include "MinhaString.h"
agora eu vou colocar using namespace MinhasCoisasDeString;
e ai eu uso normalmente o meu .h.
Se eu não colocasse namespace aqui
ai eu tenho que no código usar o operador de pertencimento para indicar onde as coisas vem.
Aqui, por exemplo nessa caso eu não coloquei o using namespace ,
para criar o "S1", "S2", "S3"
eu tenho que usar MinhaString, que pertence a nome de espaço MinhasCoisasDeString, que está lá em MinhaString.h
Ou seja, ou faço assim como está no slide, ou eu faço assim da maneira que vocês estão acostumados, suponho,
ou eu faço assado.
É muito legal porque eu posso, como já disse,
colocar namespace distribuído em vários .h.
Vamos dar um exemplo.
Imagine que você tenha uma classe, num jogo que você está fazendo, chamado FlaFla.
Nome bonito, né? Classe FlaFla,
que não significa nada para quem olha para o nome da classe.
Ai você vê classe FlaFla derivada de FluFlu,
também não significa nada, talvez signifique em determinado contexto,
mas para genericamente não significa nada.
Se eu quero dar uma significância para a classe FlaFla, que tem que se chamar Flafla,
eu posso colocar dentro de um namespace chamado Inimigos, por exemplo, posso ter um namespace Inimigos.
namespace Inimigos, abro chaves e fecho chaves e dentro coloco classe FlaFla, dentro do FlaFla.h.
Eu tenho outra classe lá, a classe FluFlu.
Também dentro do FluFlu.h vou colocar namespace Inimigos,
mesmo nome que tem no outro .h, abro chaves e fecho chaves,
lá dentro vou ter a classe FluFlu.
Então o namespace pode estar espalhado, como eu disse, em diversos .h,
de maneira tal que hora que hora que eu for utilizar as classes, por exemplo as classe FlaFla e FluFlu,
então vai ter lá:
#include "FlaFla.h" #include "FluFlu.h" using namespace Inimigos;
Dessa maneira o namespace Inimigos acabou ficando transversal ao FlaFla.h e o FluFlu.h.
E como o FlaFla e FluFlu são mnemônicos que geralmente não significam nada no português,
quando você coloca o namespace Inimigos você fala: "Ah, FlaFla é um inimigo", "Ah, FluFlu é um inimigo".
Ele dá a conotação para entendimento para as duas classes no contexto dado.
Aqui por exemplo eu tenho o namespace MinhasCoisasDeString, eu tenho a classe MinhaString.
Eu podia ter uma outra classe chamada Texto.h.
Eu ia ter a classe Texto, só que a classe Texto também ia estar englobada
lá naquele Texto.h,
pelo namespace MinhasCoisasDeString, abrindo e fechando chaves.
Então o namespace MinhasCoisasDeString estaria na MinhaSting.h
e estaria no Texto.h, por exemplo.
Mostrando que tem uma transversalidade possível.
Eu lembro de um trabalho que uma dupla fez, onde um aluno queria destacar que trabalhou muito mais que o colega.
Então todas as classes que ele fez ele colocou o namespace Fulano,
namespace Fulano e tinhas as classe Personagem.h,
no outro .h, Professor.h ele criava de volta o namespace
recolocava namespace Fulano, com a classe Professor e assim vai.
Basicamente, o que ele quis fazer com o namespace foi destacar que ele tinha trabalhado muito mais que o colega.
Maneira peculiar de usar o namespace, mas eu bati o olho e já vi
essas classes foram feitas pelo Fulano por causa do namespace, e aquelas foram feitas pelo Ciclano.
Não sei se chega a ser um uso fidedigno, mas sei que funcionou para eu saber quem tinha feito o que.
Foi uma esperteza do rapaz de, semioticamente, contar através do namespace que ele tinha feito aquilo.
Muito bem.
Isso considerado vencemos o namespace e agora vamos para o último tópico dessa aula
que é Aninhamento, classes Aninhadas, Nested.
O que é uma classe aninhada?
Uma classe aninhada é uma classe que pode estar dentro de outra classe.
Imaginem que, por algum motivo,
Eu acho que é pertinente eu ter dentro da classe nova que estou propondo aqui, do ConjuntoStrings,
ter dentro dela a classe MinhaString.
Ai, obviamente, que aqui nesse exemplo eu ia descartar o MinhaString.h,
substituindo pelo ConjuntoStrings.h
onde agora eu mantenho o namespace,
que podia inclusive continuar chamando de MinhasCoisasDeString,
Aqui na verdade eu mantenho o namespace, mas não estou mais chamando MinhasCoisasDeString, estou chamando de MinhasClasse,
que não é um nome bom, inclusive,
o nome MinhasCoisasDeString talvez fosse melhor, mas tudo bem.
Aqui eu usei outro nome para esse namespace aqui.
O fato é que eu tenho aqui dentro classe ConjuntoStrings
que começa aqui e termina ali, veja que está em vermelho inclusive,
e eu tenho, dentro da classe ConjuntoStrings, outra classe definida dentro dela,
que é a classe MinhaString que começa ali e termina aqui.
Professor, então eu posso definir uma classe dentro da outra?
Sim pode, tanto é que estou fazendo isso.
Entretanto o fato de eu ter uma classe aninhada, como essa classe em azul aqui,
dentro de outra classe, que é o caso da classe em vermelho,
não significa que eu tenho, implicitamente, objetos de um na outra.
Aqui se eu quero que ConjuntoString tenha um vetor ou um conjunto de objetos MinhaString,
eu tenho que criar explicitamente, que é o que eu fiz aqui Vet de 1000 objetos de MinhaString (MinhaString Vet [1000])
Se eu não tivesse isso aqui,
apenas uma classe estaria definida dentro da outra, ConjuntoStrings não teria objetos dela.
Aqui eu tenho uma função imprimeVet que, supostamente, vai percorrer o vetor e imprimir cada uma das strings.
Essa função pertence a ConjuntoStrings,
e também classe MinhaString pertence a ConjuntoStrings, ainda que ela seja uma classe em si.
E por que eu vou definir uma classe dentro da outra quando as coisas são extremamente íntimas?
Quando as coisas são muito íntimas a gent e vai definir uma coisa dentro da outra.
Muito bem.
Temos algum outro exemplo de intimidade de classes?
Sim, por exemplo quando a gente criava aquelas listas específicas.
A ListaAlunos você tinha o ElementoAluno,
ElementoAluno é uma coisa extremamente íntima de ListaAlunos,
de forma tal que eu poderia fazer com que a classe ElementoAluno fosse aninhada dentro da classe ListaAlunos.
Outro exemplo a classe ElementoTemplate,
ela é tão íntima da classe ListaTemplate que eu posso aninhar ElementoTemplate em ListaTemplate.
É possível aninhar templates?
É possível, ainda que tenha peculiaridades é possível.
Muito bem.
Voltando ao modo exibição.
ConjuntoStrings.h está aqui definido uma classe dentro da outra,
a classe em azul está aninhada dentro da classe em vermelho.
Como que fica a implementação?
Na implementação desse ConjuntoStrings.cpp
eu vou estar implementado o que?
Eu vou estar implementando o que está dentro do ConjuntoStrings.
Dentro do ConjuntoStrings.h eu tenho o namespace
então eu coloquei aqui using namespace MinhasClasses,
insisto esse não é um nome muito simpático, mas tudo bem é o nome que foi posto.
E agora eu tenho que implementar duas classes.
Tenho que implementar o que está na classe ConjuntoStrings, por exemplo imprimeVet,
que é retorno void, conjunto de parâmetros vazio, é uma função constante e vai ter um código aqui dentro, obviamente,
vai percorrer o vetor e imprimir cada string que está nele.
Além de implementar o conjunto de funções de ConjuntoStrings
eu tenho que implementar as próprias funções das classes aninhadas em ConjuntoString.
E como que eu faço isso?
Faço assim, não mudo muita coisa.
Vou pegar um exemplo aqui o getString.
getString é uma função constante que tem essa implementação aqui, conjunto de parâmetros vazio,
que pertente a MinhaString, que por sua vez pertence a ConjuntoStrings, e aqui está o retorno da função.
Então, além de contar o pertencimento da classe, eu conto que a classe em questão pertence a outra classe.
Outro exemplo o getNomeClasse,
que é uma função estática provavelmente, sim estática.
getNomeClasse que tem um conjunto de funções vazio, pertence a MinhaString,
que por sua vez pertence a ConjuntoStrings e está aqui o tipo de retorno.
Então o que muda é que você tem que adicionar que a classe em questão pertence a outra classe do ponto de vista de aninhamento.
Então é isso, pessoal.
Uma classe aninhada está dentro da outra,
e o motivo para ter uma classe aninhada dentro de outra é a intimidade entre as classes.
Aqui MinhaString é extremamente íntima em relação a ConjuntoStrings.
Na implementação das funções de uma classe aninhada,
além de contar que a função pertence a classe em si, tem que contar que a classe pertence a outra classe do ponto de vista de aninhamento.
A utilização também não tem maiores dificuldades,
você vem aqui e faz "S1", "S2" e "S3" do tipo MinhaString, sendo que MinhaString pertence a ConjutoStrings.
Então sem maiores problemas.
Eu também posso criar além de objetos da classe que está aninhada, MinhaString, em ConjuntoStrings,
eu posso criar objetos do próprio ConjuntoString, obviamente, como vocês estão vendo aqui.
Aqui eu proponho o exercício 1.
Que é voltar lá naquelas versões de códigos que você tem,
eu imagino que você tem várias versões, cada slide que a gente faz provê uma versão ou mais do sistema acadêmico,
você está versionando isso, criando um sistema de versionamento seu,
você pode voltar em uma das versões onde tem a classe ListaAluno ainda com o ElementoAluno dentro de si
criar um versão X', e nessa versão você vai fazer isso aqui,
fazer com que o ElementoAluno seja uma classe aninhada privada de ListaAlunos.
Tem diferença entre um elemento aninhado privado e público.
Se ela é privada, trás algumas dificuldades,
por exemplo aqui o aninhamento de MinhaString é um aninhamento público, está na parte pública não na parte privada.
Em sendo público eu consigo criar objetos da classe aninhada, mesmo na função main ou em uma função fora.
Está aqui, eu consigo fazer "S1", "S2" e "S3" do tipo MinhaString.
Por quê? Porque MinhaString está na parte pública de ConjuntoStrings.
Então tome um pouco de cuidado em relação a classe aninhada pública e classe aninhada privada.
Tem o exercício 2 ainda.
Fazer com que o Elemento seja uma classe aninhada pública de Lista.
Outramente dito, fazer com que o ElementoTemplate seja aninhado publicamente na ListaTemplate.
Lá na minha página, inclusive, onde está o grupo de slides 12, que é esse grupo de slides em questão,
tem uma dicas de como fazer esse exercício,
em algum lugar onde esse exercício está resolvido se você quiser buscar inspiração.
Uma dica que eu dou em relação a esse exercício é que na classe Elemento,
para facilitar a utilização do operador :: de pertencimento
para facilitar esse uso, no tocante da classe Elemento, faça a classe Elemento implementada tudo de maneira in line,
ou seja, define a função e já implementa.
Não separa a implementação em definição e implementação no caso de elemento.
Elemento tem que estar aninhado em Lista, insisto.
Nesse caso você pode pegar a classe Elemento só ela, ElementoTemplate, já fazer a definição das funções e a implementação.
Como o Elemento são funções pequenas
não tem problema nesse caso dado a implementação ficar junto da definição, vai ser uma casa toda in line, na linha.
Pessoal, espero que vocês tenham aproveitado essa aula, teve uma série de conceitos legais.
A gente revisa const e lembra que tem, ademais,
parâmetro constate, retorno constate, atributo constante, tem também função constante.
Nós aprendemos, além de função constante, aprendemos depois
a questão estático, de ter atributo estático com funções estáticas,
que são atributos e funções de classe, compartilhados entre os objetos daquela classe.
Nós temos também a noção de espaço de nomes, namespace,
que permite dar uma melhor conotação às classes
e também criar um agrupamento entre classes transversal, de maneira transversal nos diversos .h.
Por exemplo se eu tiver FlaFla, FleFle, FliFli, FloFlo, FluFlu enquanto classes,
o nome dessas classe não fazem muito sentido do ponto de vista genérico,
agora se ela estiverem todas no namespace Inimigos, fica claro identificar transversalmente nos .h
que lá FlaFla.h, FleFle.h e etc,
que na verdade isso é um conjunto de Inimigos, conjunto de tipos de Inimigos.
Bom, e ainda a gente tem por fim o último conceito visto nessa aula que foi o nested, aninhado,
mostrando que uma classe pode ser definida dentro da outra quando tem intimidade o suficiente para isso.
Quando uma classe é muito íntima da outra, faz sentido criar um aninhamento de classes para aumentar coesão e desacoplamento.
Particularmente coesão nesse caso posto.
Pessoal, espero que tenham aproveitado a aula.
A gente aqui venceu, na prática, os principais conceitos de orientação a objetos.
Agora as próximas aulas são mais utilização de elementos de c++, como classe String,
a gente vai também dar uma olhada nos templates, revisitar os templates que existem prontos no STL, no c++,
particularmente no STL que é Standard Template Library,
já sublinhando List e Vector, e por ai vai.
Então, conceitualmente, do ponto de vista da orientação a objetos pura,
a gente venceu os principais conceitos que vocês tinham que aprender.
Depois tem outros conceitos que são importantes,
mas ai já é ação conjunta com orientação a objetos e não necessariamente da orientação a objetos propriamente dita.
Bons estudos, e até o próximo encontro.