Teoria

E aí pessoal, aqui é o Juan do Responde Aí, e hoje vamos bater um papo sobre os templates!

Funções que recebem vários tipos diferentes.

Imagine que você está criando uma função chamada soma que retorna os mesmos tipos que recebe. Ou seja, uma soma de tipos inteiros retorna inteiros, uma soma de tipos f l o a t retorna f l o a t . Provavelmente você iria criar uma função sobrecarregada dessa forma:

No exemplo acima a gente criou uma função chamada s o m a que recebe dois inteiros e retorna um inteiro como resultado. Logo abaixo a gente sobrecarregou essa função, criando uma outra função com o mesmo nome, porém recebendo parâmetros do tipo f l o a t e retornando um valor do tipo f l o a t .

E se a gente quisesse uma função que recebe e retorna d o u b l e ? Então teremos que fazer mais uma sobrecarga! Acontece que ficar copiando e colando o código pra criar novas sobrecargas é um processo bem chato. E ter muitas sobrecargas vai deixar o nosso algoritmo bagunçado e difícil de ler.

O ideal seria construir uma função que se adapte a qualquer tipo. A boa notícia é que o C++ tem um recurso chamado t e m p l a t e . Com os t e m p l a t e s poderemos reutilizar boa parte dos códigos que desenvolvemos em casos assim.

Construindo um t e m p l a t e de função

Para construir o template de uma função, basta a gente usar as palavras-chave t e m p l a t e e t y p e n a m e para criar um prefixo de template na mesma linha em que criamos a função:

t e m p l a t e < t y p e n a m e   N o m e T i p o > t i p o D a F u n c a o   n o m e D a F u n c a o (   p a r a m e t r o s   )

Veja o exemplo:

Na linha 04 a gente criou um tipo genérico chamado M y T y p e , e criamos um template de função chamado s o m a que recebe dois parâmetros do tipo M y T y p e e retorna um resultado do tipo M y T y p e .

E agora que temos um template de função criado, é só a gente utilizar a função normalmente, que o compilador vai identificar os tipos envolvidos e vai usar o M y T y p e da maneira correta.

Na linha 09 usamos valores inteiros, e o C++ identificou o tipo i n t e tratou o tipo genérico M y T y p e como um tipo i n t . Na linha 10 ocorre o mesmo fenômeno, onde o C++ identifica as entradas de tipo f l o a t e trata o M y T y p e como se fosse f l o a t . E na linha 11 são inseridos valores de tipo c h a r , e o C++ efetua uma soma de c h a r s .

Mas podem existir situações em que vamos querer forçar o template a trabalhar com um tipo específico. Para isso basta colocar o nome do tipo específico < t i p o > . Na linha 13 a gente força o M y T y p e a trabalhar como tipo d o u b l e .

Viu que legal! A gente criou apenas um template de função, e mesmo assim ele consegue se adaptar corretamente aos vários tipos de dados diferentes. Com sobrecarga precisaríamos copiar e colar essa função ao menos 4 vezes.

Detalhando a passagem de parâmetros em templates de funções

Os templates de função funcionam muito parecido com as funções normais que já estamos acostumados.

Da mesma forma como as funções normais, os templates de função podem receber vários tipos de dados diferentes, podem receber parâmetros através de passagem por referência ou passagem por ponteiro.

E se for necessário, você pode criar um template que recebe vários tipos genéricos ao mesmo tempo. É só declarar cada um dos tipos dentro do prefixo da função: t e m p l a t e < t y p e n a m e   T i p o 1 , … , t y p e n a m e   T i p o N   >

Construindo t e m p l a t e s de classes

Na hora de construir um template pra uma classe basta a gente utilizar o prefixo de template na mesma linha em que criamos a classe:

t e m p l a t e < t y p e n a m e   N o m e T i p o > c l a s s   n o m e C l a s s e

E agora podemos usar o tipo genérico em qualquer parte da nossa classe, veja o exemplo:

Na linha 05 usamos o prefixo de template para criar o tipo genérico M e u T i p o e iniciamos o template de classe chamado M i n h a C l a s s e . Na linha 07 criamos um construtor que recebe um parâmetro do tipo M e u T i p o , na linha 13 desenvolvemos um método que recebe um parâmetro de tipo genérico, e na linha 17 criamos um atributo do tipo genérico.

Na hora de instanciar um objeto, a melhor forma é declarar explicitamente o tipo entre <   > , como fazemos na linha 23 criando um objeto chamado m e u O b j e t o onde o tipo genérico M e u T i p o e substituído pelo tipo inteiro i n t .

Aqui só precisamos ter cuidado quando a gente quiser desenvolver um método fora das chaves da classe. Quando você fizer isso, vai ser necessário usar o prefixo de template na classe e na função membro também!

Na linha 04 criamos um template de classe chamado E x e m p l o , e declaramos um método publico do tipo T y p e que chamamos de m e t o d o . Na hora de desenvolver o método, na linha 10, a gente cria um template deste método, como fizemos com os templates de função.

Mais detalhes sobre templates de funções

Alguns professores substituem a palavra-chave t y p e n a m e por c l a s s . Mas no contexto de templates elas significam a mesma coisa.

t e m p l a t e < t y p e n a m e   T i p o > ⇔ é   o   m e s m o   q u e t e m p l a t e < c l a s s   T i p o >

Mas dê preferência em usar o t y p e n a m e que é uma palavra-chave mais moderna.

Alguns erros comuns são:

  • Esquecer das palavras-chave t e m p l a t e   ou t y p e n a m e
  • Esquecer de usar o prefixo de template antes do nome da função ou da classe

E por hoje é isso pessoal! Vamos pros exercícios de fixação!

Construindo um t e m p l a t e de função

Detalhando a passagem de parâmetros em templates de funções

Construindo t e m p l a t e s de classes

Mais detalhes sobre templates de funções

Exercícios Resolvidos

Exercício Resolvido #1

Explique o que são templates e como podem ser úteis.

Passo 1

Os templates são alternativas as sobrecargas de funções. Eles permitem que os programadores reutilizem uma boa parte do código, criando definições genéricas para funções e classes, capazes de se adaptar a diferentes tipos de dados. Os templates são especialmente úteis quando uma mesma lógica é aplicável a diversos tipos de dados. E como desvantagem, um código com templates pode ter um tempo de compilação maior.

Quando criamos um template desenvolvemos um código com um “tipo de dado genérico”, e no momento da utilização este tipo genérico é capaz de se adaptar automaticamente aos tipo dados reais que são inseridos nas funções ou classes.

Para construir um template basta adicionar a expressão t e m p l a t e < t y p e n a m e   T i p o G e n e r i c o > junto com a declaração da função ou classe, e usar o T i p o G e n e r i c o para receber dados e desenvolver o código.

Na hora de usar um template, é só usar a função normalmente, ou instanciar um objeto da classe de maneira usual, e o próprio C++ irá identificar os tipos inseridos e automaticamente adaptar o T i p o G e n e r i c o para o tipo real inserido. Mas podemos utilizar as chaves < > para determinar explicitamente os tipos que devem ser usados.

Resposta

Ei, a resposta está no passo a passo :)

Exercício Resolvido #2

O código abaixo contém alguns erros. Identifique e corrija.

Passo 1

Vamos nessa, galerinha!

Essa é uma daquelas questões de encontrar erros. A melhor forma de resolver é olhar cada uma das linhas e procurar por problemas.

Passo 2

Os problemas começam a aparecer na linha 04.

Se você olhar com atenção, vai notar que o sufixo de template está errado. A forma correta do sufixo é:

t e m p l a t e < t y p e n a m e   N o m e T i p o >

O primeiro erro é que a linha começa com a palavra-chave errada, o correto é iniciar um template usando a palavra chave t e m p l a t e .

O segundo erro é que a palavra-chave t y p e n a m e está no lugar errado. O correto é usar o t y p e n a m e   dentro dos símbolos <   > .

E existe mais um erro, o uso inadequado do ponto-e-vírgula ; . Esse símbolo não deve ser usado no final do template. Lembre-se que o sufixo de template faz parte da declaração da função.

No caso desse código o nome do tipo genérico é T , então com isso está tudo certo.

Vamos aplicar estas correções no código:

Passo 3

Vamos pra linha seguinte. Na linha 05 nós fazemos a declaração do template de função propriamente dito.

A vantagem do template é que ele pode usar o tipo genérico T que foi definido na linha anterior.

Mas a um erro na linha 05, os parâmetros da função não estão declarados corretamente. O segundo parâmetro não possui nenhum tipo!

Vamos fazer a correção. Vamos adicionar o tipo genérico T logo antes do parâmetro y na linha 05:

Passo 4

Show de bola

Olhando pras próximas linhas, tudo parece está certo agora. Mas pra ter certeza, vamos rodar o código usando as correções que fizemos na linha anterior.

E prontinho. Código rodando liso que nem manteiga!

Resposta

Exercício Resolvido #3

Estude o seguinte código

Existe um o erro produzido pelo terceiro c o u t .

  1. Explique o motivo deste erro.
  2. Corrija o erro sem alterar o conteúdo entre parêntesis.

Passo 1

E aí galerinha. Vamos pra mais um exercício maneiro.

  1. Explique o motivo deste erro.
  2. Esse é um daqueles exercício em que o código tem um erro. Esse é um erro um tanto difícil de encontrar apenas olhando, mas pra nossa sorte a questão já informou que o erro está no terceiro c o u t , o da linha 14.

    O erro é sutil, e pra entender a gente precisar olhar antes pra definição de template nas linhas 04 e 05

    Olha só, na declaração da função-template definimos os dois parâmetros x e y usando o mesmo tipo genérico T .

    Agora vamos olhar pra linha 14, que é onde o compilador avisa do erro. Nessa linha, a gente entrega pra função dois parâmetros de tipos diferentes. O 3 é um inteiro, e o 7.0 é um f l o a t .

    Quando o compilador tentar rodar essa linha ele vai ficar doidinho. Pois ele não vai saber se o tipo genérico T deve ser considerado como i n t , ou se deve ser considerado como f l o a t .

    Se você tentar rodar esse código, o seu compilador vai informar um erro parecido com esse:

    Que basicamente está dizendo “não existe um template chamado M a x em que os parâmetros possam ter tipos diferentes!”

    Passo 2

  3. Corrija o erro sem alterar o conteúdo entre parêntesis.

Belezinha. Identificamos o erro, e já explicamos o motivo de ele acontecer. Mas como corrigimos isso?

Uma forma de corrigir o erro seria trocando o valor entre parêntesis, para que os dois valores sejam do mesmo tipo. Porém a questão falou que a gente não pode fazer isso.

A forma mais fácil de corrigir esse erro é forçando que o valor de T assuma um tipo predeterminado. Pra fazer isso, a gente pode colocar o tipo que queremos definir dentro de chaves <   > logo depois do nome da função e antes dos parêntesis:

N o m e F u n c a o T e m p l a t e < t i p o > ( p a r a m e t r o s )

Então, pra corrigir o código, é só a gente ir na linha 14 e forçar que a função template utilize um tipo específico. Para garantir maior precisão, vou forçar o uso do tipo f l o a t

Passo 2

Agora o código está corrigido! Mas pra garantir, vamos colocar o código pra rodar e ver o resultado:

E aí está. Tudo rodando certinho!

Até a próxima questão, galera!

Resposta

Ei, a resposta está no passo a passo :)

Exercício Resolvido #4

Utilizando templates, escreva uma função que receba dois números e imprima a soma na tela.

Passo 1

Vamos lá galerinha.

A questão quer que a gente crie uma função para somar dois números. Mas o diferencial é que vamos utilizar templates.

A vantagem de usar templates é que a função vai conseguir se adaptar a qualquer tipo de dado que for inserido na nossa função.

Então vamos começar escrevendo o cabeçalho do nosso programinha.

Passo 2

Vamos começar desenvolvendo a nossa função template.

Sempre que for começar um template iniciamos com a palavra-chave t e m p l a t e e em seguida definimos os nomes dos tipos genéricos entre as chaves < > usando a palavra chave t y p e n a m e .

t e m p l a t e < t y p e n a m e   N o m e T i p o >

Vamos por isso no código. Eu vou chamar o tipo genérico de T , mas se você quiser pode dar outro nome.

Agora, usando o tipo genérico T a gente desenvolve a função template chamada s o m a e que recebe dois parâmetros x e y que também usam o tipo genérico.

Fazendo isso, a nossa função vai poder receber qualquer tipo de dado, e o retorno da função também vai se adaptar aos tipos de dados.

E essa função vai retornar a soma entre os dois parâmetros inseridos.

Show. O template de função está concluído.

Passo 3

Beleza.

Agora vamos testar o template que a gente desenvolveu. Para testar vamos fazer várias somas inserindo parâmetros com tipos variados.

Na linha 14 inserimos tipos diferentes no mesmo template, então usamos as chaves < > para forçar que os parâmetros sejam recebidos como tipo d o u b l e .

E rodando o código a gente vai ter o seguinte resultado:

E é isso pessoal. Até o próximo exercício.

Resposta

Exercício Resolvido #5

Crie uma classe que represente um ponto com duas dimensões. Cada ponto pode ser criado com valores inteiros ou reais. Os atributos devem ser privados, devem existir getters e setters para acessá-los. Os valores iniciais do ponto devem ser inseridos no momento em que um objeto é criado.

Passo 1

Vamos lá pessoal. Essa questão está pedindo pra gente criar uma classe para representar um ponto, mas com alguns detalhes:

O exercício pede que a classe aceite que os valores sejam inteiros ou reais. Uma forma de fazer isso é desenvolvendo uma classe template. Vamos usar um tipo genérico para desenvolver um código, e esse tipo genérico vai se adaptar conforme a necessidade.

Os atributos devem ser privados, então vamos desenvolver métodos gettes e setters. O detalhe é que esses métodos devem ser projetados usando o tipo genérico. Assim, eles poderão se adaptar a qualquer tipo de dado usado na classe.

Para inserir os valores no momento da criação vamos precisar de um método construtor. O detalhe é que esse método também deve usar o tipo genérico. E dessa forma o construtor vai trabalhar com os tipos adequados.

Mas antes de começar tudo isso, vamos escrever o cabeçalho:

Passo 2

Agora é hora de desenvolver o template da classe. Pra desenvolver um template sempre começamos com a sintaxe:

t e m p l a t e < t y p e n a m e   n o m e T i p o > c l a s s   n o m e C l a s s e

No nosso código vamos chamar o tipo genérico simplesmente de M e u T i p o e chamaremos o template de classe de P O N T O :

Usando esse tipo genérico vamos declarar duas variáveis x e y no contexto privado. Usando o nosso T i p o os atributos vão conseguir se adaptar para números reais ou inteiros.

Em seguida vamos desenvolver o construtor da classe. Lembre-se, o construtor é uma função sem tipo que tem o mesmo nome que a classe. Os parâmetros do nosso construtor são os valores das componentes do ponto que são do tipo genérico M e u T i p o . No corpo do construtor vamos apenas assimilar os valores inseridos dentro dos atributos privados.

O passo seguinte e desenvolver os métodos getters, pra que a gente consiga acessar os valores privados da classe. Novamente, devemos lembrar que os atributos x e y são do tipo genérico M e u T i p o , e para um método retornar o valor desses atributos, esse método deve retornar o tipo genérico também! Ou seja, os métodos g e t X (   ) e g e t Y (   ) devem ser do tipo genérico M e u T i p o :

E pra finalizar vamos desenvolver os métodos setters. Como de praxe, os setters são do tipo v o i d , afinal eles não precisam retornar nenhum valor, eles só precisam receber um parâmetro e alterar o valor de uma variável privada. O diferencial é que os parâmetros devem ser do tipo genérico M e u T i p o , pois assim os parâmetros vão combinar com as variáveis x e y que queremos alterar.

E com os dois métodos setter concluídos, o template está finalizado!

Passo 3

Show! Vamos por esse template pra trabalhar agora

Pra criar objetos partindo de um template é quase igual a criar um objeto de uma classe, porém usamos as chaves < > para determinar o tipo de dados que vai substituir o tipo genérico:

N o m e T e m p l a t e < t i p o > n o m e o b j e t o (   p a r a m e t r o s _ d o _ c o n s t r u t o r   )

Usando essa lógica, no nosso código vamos criar dois pontos com valores aleatórios:

E vamos usar os métodos getters para conferir se deu tudo certo!

E é isso, galerinha! A questão está pronta!

Resposta

Exercício Resolvido #6

Desenvolva um template que troque o valor de duas variáveis.

Passo 1

Vamos nessa!

Essa é uma questão simples e direta: construir um template para efetuar uma função de troca.

Lembre-se, uma função de troca deve receber o endereço de memória de duas variáveis, e então trocar os conteúdos existentes em cada endereço.

Então vamos começar com o cabeçalho da questão:

Passo 2

Vamos criar o template da função. Para criar um template a gente usa estrura:

t e m p l a t e < t y p e n a m e   N o m e T i p o > t i p o D a F u n c a o   n o m e D a F u n c a o (   p a r a m e t r o s   )

Vamos usar o nome T para o nosso tipo, e o nome da função será t r o c a . A função não precisa de retorno, então o tipo será v o i d . Como parâmetros vamos receber duas variáveis por referência, para ter acesso ao endereço de memória.

Importante: os dois parâmetros que vamos receber devem usar o mesmo tipo genérico T ! Pois se as variáveis forem de tipos diferentes não vai ser possível executar a troca de valores, pois será necessário efetuar conversões, o que resulta em perda de dados!

Agora vamos desenvolver o algoritmo da função.

Primeiro vamos declarar uma variável temporária que vai segurar o valor atual de a .

Depois, sobrescrevemos o valor atual de a com o valor de b .

E pra finalizar, sobrescrevemos b com o valor antigo a que está guardado na variável temporária.

Detalhe, como os valores de a e b foram passados por referência, automaticamente as alterações realizadas dentro da função, serão refletidas nas variáveis que estão fora da função!

Passo 3

Show de bola! Agora é só executar a função!

Vamos declarar duas variáveis a e b com os valores 10 e 5 . E pra deixar bem legal, vamos imprimir o conteúdo dessas variáveis para o usuário.

Em seguida, vamos aplicar a função troca:

E imprimimos o resultado final:

E o resultado é:

Legal né! Lembrando que isso é um template. Então podemos usar variáveis de qualquer tipo e vamos obter um resultado semelhante!

Resposta

Exercício Resolvido #7

Considere as seguintes definições de templates das funções x p t o , y p t o e z p t o .

E considere as classes t d a t a , t h o r a r i o e t d i m e n s a o

Indique quais das linhas de código de m a i n abaixo são legais e explique as que não são.

Passo 1

E aí, pessoal?!

Essa é uma questão trabalhosa, mas que vamos fazer com calma e vai dar tudo certo. A chave da questão é perceber como cada um dos tipos genéricos vai se comportar quando uma função é chamada.

Vamos começar analisando os templates.

Vamos começar observando as classes t d a t a , t h o r a r i o e t d i m e n s a o

As três classes são bem similares, e consistem em apenas três atributos inteiros.

São classes sem função real, e tudo que importa pra essa questão é que elas representam tipos diferentes!

Agora vamos analisar as aparições dessas classes na m a i n (). Logo no início são declarados um objeto de cada uma das classes: a do tipo t d a t a , b do tipo t h o r a r i o e c do tipo t d i m e n s ã o .

Passo 2

Vamos analisar o template x p t o

O template de função x p t o usa apenas um tipo genérico chamado T . Ele recebe dois valores do mesmo tipo e retorna como resultado o segundo valor. Ou seja, x p t o recebe e retorna valores todos do mesmo tipo!

Agora vamos analisar as aparições da função x p t o dentro da m a i n .

Esse template de função deve receber dois argumentos e um retorno do mesmo tipo. Então caso haja alguma diferença de tipo, haverá um erro.

Então podemos apontar um erro na linha 08 onde o retorno b é diferente do tipo do argumento a .

E um outro erro na linha 09 onde os três tipos envolvidos são diferentes.

Passo 3

Em seguida, vamos analisar y p t o .

O template de função y p t o utiliza dois tipos genéricos T e U . Essa função recebe dois valores, um de cada tipo, e retorna o segundo valor recebido. O importante é que na função y p t o o retorno é do mesmo tipo que o segundo argumento.

Agora vamos ver y p t o dentro da m a i n

Aqui o importante é que o tipo do retorno seja igual ao tipo do segundo argumento.

E por isso temos um erro na linha 13 onde os tipos b e a são diferentes.

E na linha 15 onde c e b são de tipos diferentes.

Passo 4

E por fim, a o template de função z p t o .

O template de função z p t o utiliza três tipos genéricos T , U e V . Os valores recebidos são de tipos diferentes e antes de retornar, a função z p t o converte o tipo de y para V . Ou seja, a função z p t o pode receber dois argumentos de tipos diferentes, e retornar um valor de um terceiro tipo.

Porém, tem um detalhe. O prefixo de z p t o declara três tipos genéricos T , U e V . O tipo real de T será definido quando for passado o primeiro argumento x . O tipo de U será definido de acordo com o segundo argumento y . Mas em que momento o tipo real de V está sendo definido?

O tipo de V não é definido em nenhum momento! Então para usar esse template, a única forma é definindo os tipos de T , U e V de forma explicita usando as chaves: < t i p o 1 ,   t i p o 2 ,   t i p o 3 >

Em nenhum momento o tipo verdadeiro de V está sendo definido de forma explicita! Então todos os usos de z p t o mostrados no código estão errados.

Passo 5

Para corrigir esse código, primeiro vamos precisar remover as linhas 08 e 09

Depois, devemos remover as linhas 13 e 15.

E nas linhas 19 a 22 devemos adicionar explicitamente os tipos que estão sendo usados no template:

E é isso pessoal! Até a próxima!

Resposta

Exercício Resolvido #8

Crie um template de classe que representa um vetor de qualquer tipo. O tamanho desse vetor deve ser definido dinamicamente no momento da criação do objeto. Efetue a sobrecarga do operador colchetes   para que a gente possa acessar facilmente um elemento do vetor.

Passo 1

Vamos nessa, pessoal.

Nesse exercício envolve um monte de conhecimentos: templates, alocação dinâmica e sobrecarga de operador. É bastante coisa! Mas vai ser divertido fazer essa questão.

A questão pede pra criar um template de classe que represente um vetor, então vamos chamar essa template de V e t o r .

Dentro do template V e t o r vamos ter que usar um array alocado dinamicamente para armazenar os elementos do nosso vetor. Se você se lembrar, a melhor forma de fazer isso é alocando a array dentro do construtor, e liberando a memória dentro do destruidor. Depois vamos sobrecarregar o operador   .

Então vamos começar com o cabeçalho da questão:

Passo 2

Então vamos declarar o template de classe V e t o r , e dentro do template vamos declarar o protótipo de todos os métodos.

Para criar um template de classe a gente utiliza a palavra-chave t e m p l a t e e determinamos um tipo genérico usando t y p e n a m e e em seguida declaramos a classe:

t e m p l a t e < t y p e n a m e   N o m e T i p o G e n e r i c o > c l a s s   N o m e C l a s s e

Template iniciado. Agora vamos pro encapsulamento privado, e declaramos o atributo ponteiro p n t V e t o r usando o tipo genérico T . Afinal de contas, é esse ponteiro que vamos usar para alocar a memória dinamicamente, então ele precisa apontar para o tipo que vamos utilizar no nosso template.

O tamanho do V e t o r sempre será um valor inteiro, então criamos um atributo t a m a n h o que vai armazenar a quantidade de elementos do V e t o r .

Agora vamos para o encapsulamento público. Aqui vamos criar o protótipo de todos os nossos métodos

Primeiro declararmos o construtor, que é um método sem tipo, e que vai receber o valor inteiro de t a m a n h o . Ou seja, é só declarar um construtor normalmente.

Depois declaramos o destruidor, que também é um método sem tipo, então é só declarar um destruidor normalmente.

Agora vamos pensar na sobrecarga do operador   . O primeiro detalhe é que esse operador só pode ser sobrecarregado como função-membro da classe.

t i p o   o p e r a t o r   S i m b o l o D o O p e r a d o r   (   p a r a m e t r o s   )

O símbolo do operador é   , e o parâmetro que vamos receber é o índice a ser acessado. O segundo detalhe é que o tipo da função será T & !

O tipo é T pois o operador vai retornar um elemento do V e t o r e o tipo dos elementos do V e t o r são determinados de acordo com o tipo genérico do template. O símbolo & está aí, pois queremos retornar uma referência para o valor do V e t o r , isso torna possível que o valor seja alterado se necessário.

Pronto. O protótipo do template está desenvolvido. O próximo passo é desenvolver o conteúdo dos métodos.

Passo 3

O primeiro método que vamos desenvolver é o construtor.

Aqui temos que notar uma pequena diferença. Quando queremos desenvolver um método que foi declarando dentro de um template, nós temos que adicionar o prefixo de template, e antes do operador temos que adicionar os tipos genéricos entre chaves.

Ou seja, um método de template tem que ser escrito que nem um template de função, mas adicionando o nome da classe com o operador , da seguinte forma:

t e m p l a t e   < t y p e n a m e   T >   t i p o   N o m e C l a s s e < T > : : N o m e M e t o d o (   p a r a m s   )

O construtor é um método sem tipo de retorno e com o mesmo nome da classe, então fica assim:

t e m p l a t e   < t y p e n a m e   T >   V e t o r < T > : : V e t o r ( i n t   t a m a n h o )

Dentro do construtor, a primeira coisa a ser feita é inicializar o parâmetro t a m a n h o

Em seguida, alocamos no ponteiro p n t V e c t o r um array dinâmico com a dimensão t a m a n h o :

Prontinho! O array dinâmico foi criado com sucesso. Agora, vamos usar um loop f o r para pedir pro usuário preencher cada uma das posições do array:

Passo 4

Agora vamos desenvolver o destruidor. Novamente precisamos lembrar que um método de template tem que ser escrito que nem uma função template, mas adicionando o nome da classe e o operador , da seguinte forma:

t e m p l a t e   < t y p e n a m e   T >   t i p o   N o m e C l a s s e < T > : : N o m e M e t o d o (   p a r a m s   )

Dentro do destruidor temos que liberar a memória que foi alocada dinamicamente. Para isso vamos usar o operador d e l e t e   [   ] para apagar o conteúdo do endereço de memória apontado por p n t V e t o r .

E é só isso. O destruidor está prontinho!

Passo 5

Agora vamos dar uma olhada detalhada na sobrecarga do operador   . Novamente, quando escrevemos um um método de template precisamos adicionar os prefixos de template:

t e m p l a t e   < t y p e n a m e   T >   t i p o   N o m e C l a s s e < T > : : N o m e M e t o d o (   p a r a m s   )

No caso da sobrecarga do operador   o tipo de retorno é T & .

A principal função desse operador é mostrar o conteúdo existente um uma posição do array. Dentro do colchete a gente escreve um índice, e o operador sobrecarregado retorna a posição correspondente do array.

E é só isso! Usando o & no retorno da sobrecarga a gente possibilita mais usos do operador [   ] .

Com isso a classe está concluída, e só falta a gente testar.

Passo 6

Agora só falta a gente testar pra garantir que tudo funciona!

Vamos criar um objeto do tipo V e t o r e vamos inicia-lo com tamanho 5 . Assim que o objeto for criado o construtor vai entrar em ação, e vai pedir que a gente preencha o vetor. Para fins de testes, vou imprimir o conteúdo da posição 3 .

Em seguida vamos criar um outro objeto da classe V e t o r , mas dessa vez usando o tipo f l o a t . E vamos imprimir a primeira posição desse objeto.

E pronto, vamos rodar o programa:

E o programa rodou tranquilamente. Como estamos usando templates, foi super tranquilo alterar o tipo de dados usado no Vetor!

E veja só a última mensagem: é o destruidor entrando em ação e limpando a memória.

E por hoje é isso! Até a próxima!

Resposta