Menu
Coddy logo textTech

Templates de Classe

Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy — lição 65 de 104.

Assim como os templates de função permitem que você escreva funções independentes de tipo, os templates de classe permitem que você crie classes independentes de tipo. É assim que containers como std::vector funcionam - você define a estrutura uma vez, e o compilador gera versões específicas para cada tipo que você utiliza.

template <typename T>
class Box {
    T value;
public:
    Box(T v) : value(v) {}
    T getValue() const { return value; }
    void setValue(T v) { value = v; }
};

int main() {
    Box<int> intBox(42);
    Box<std::string> strBox("Hello");
    
    std::cout << intBox.getValue() << std::endl;  // 42
    std::cout << strBox.getValue() << std::endl;  // Hello
}

Ao contrário dos templates de função, você deve especificar explicitamente o tipo ao criar objetos a partir de templates de classe usando colchetes angulares. O compilador então gera uma definição de classe completa para esse tipo específico.

Templates de classe podem ter múltiplos parâmetros de tipo e até mesmo parâmetros que não são de tipo, como inteiros:

template <typename T, int Size>
class FixedArray {
    T data[Size];
public:
    T& operator[](int index) { return data[index]; }
    int size() const { return Size; }
};

FixedArray<double, 5> arr;  // Array de 5 doubles
arr[0] = 3.14;

Ao definir funções de membro fora da classe, você deve repetir a declaração do template:

template <typename T>
class Container {
    T* data;
public:
    Container();
    ~Container();
};

template <typename T>
Container<T>::Container() : data(nullptr) {}

template <typename T>
Container<T>::~Container() { delete data; }

Templates de classe formam a base da programação genérica em C++, permitindo que você escreva estruturas de dados reutilizáveis que funcionam com qualquer tipo.

challenge icon

Desafio

Fácil

Vamos construir um sistema de armazenamento genérico usando templates de classe para criar um contêiner flexível que pode conter qualquer tipo de dado. Você organizará sua classe template em um arquivo de cabeçalho e demonstrará sua versatilidade com diferentes tipos em seu programa principal.

Você criará dois arquivos:

  • Storage.h: Defina um template de classe chamado Storage que atua como um contêiner simples para um único valor com algumas operações úteis:

    Seu template Storage deve ter:

    • Um membro privado para manter o valor armazenado
    • Um construtor que recebe um valor inicial
    • Um método getValue() que retorna o valor armazenado
    • Um método setValue() que atualiza o valor armazenado
    • Um método isEmpty() que retorna true se o valor for igual ao valor construído por padrão do tipo T, e false caso contrário

    Também crie um template de classe chamado Pair com dois parâmetros de tipo que armazena dois valores relacionados:

    • Membros privados para o primeiro e o segundo valores (de tipos potencialmente diferentes)
    • Um construtor que inicializa ambos os valores
    • Métodos getFirst() e getSecond() para recuperar cada valor
    • Um método display() que imprime: (<first>, <second>)
  • main.cpp: Leia quatro entradas (cada uma em uma linha separada):
    1. Um valor inteiro
    2. Um novo valor inteiro
    3. Um valor de string
    4. Um valor double

    Demonstre seus templates:

    1. Criando um Storage<int> com o primeiro inteiro, imprimindo: Int storage: <value>
    2. Atualizando-o com o segundo inteiro usando setValue(), e então imprimindo: Updated: <value>
    3. Criando um Storage<std::string> com a string de entrada, imprimindo: String storage: <value>
    4. Verificando se o armazenamento de string está vazio e imprimindo: Is empty: <true/false> (imprima true ou false)
    5. Criando um Pair<std::string, double> com os valores de string e double, e então chamando display()
    6. Criando um Pair<int, int> com ambos os inteiros de entrada, e então chamando display()

Por exemplo, com as entradas 42, 100, Hello, e 3.14:

Int storage: 42
Updated: 100
String storage: Hello
Is empty: false
(Hello, 3.14)
(42, 100)

Observe como o mesmo template Storage funciona perfeitamente com inteiros e strings, e como o Pair pode combinar tipos diferentes. O compilador gera definições de classe separadas para cada combinação de tipos que você usa. Lembre-se de usar a sintaxe template <typename T> para templates de tipo único e template <typename T, typename U> para templates com múltiplos parâmetros de tipo.

Experimente você mesmo

#include <iostream>
#include <string>
#include "Storage.h"

using namespace std;

int main() {
    // Ler entradas
    int intValue1;
    int intValue2;
    string strValue;
    double doubleValue;
    
    cin >> intValue1;
    cin >> intValue2;
    cin >> strValue;
    cin >> doubleValue;
    
    // TODO: Criar Storage<int> com o primeiro inteiro e imprimir: Int storage: <value>
    
    // TODO: Atualizar com o segundo inteiro usando setValue(), imprimir: Updated: <value>
    
    // TODO: Criar Storage<std::string> com a string de entrada, imprimir: String storage: <value>
    
    // TODO: Verificar se o storage de string está vazio, imprimir: Is empty: true/false
    
    // TODO: Criar Pair<std::string, double> com a string e o double, chamar display()
    
    // TODO: Criar Pair<int, int> com ambos os inteiros, chamar display()
    
    return 0;
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos