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 membros 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.
Desafio
FácilVamos 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 chamadoStorageque atua como um contêiner simples para um único valor com algumas operações úteis:Seu template
Storagedeve 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 retornatruese o valor for igual ao valor construído por padrão do tipo T, efalsecaso contrário
Também crie um template de classe chamado
Paircom 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()egetSecond()para recuperar cada valor - Um método
display()que imprime:(<first>, <second>)
main.cpp: Leia quatro entradas (cada uma em uma linha separada):- Um valor inteiro
- Um novo valor inteiro
- Um valor de string
- Um valor double
Demonstre seus templates:
- Criando um
Storage<int>com o primeiro inteiro, imprimindo:Int storage: <value> - Atualizando-o com o segundo inteiro usando
setValue(), depois imprimindo:Updated: <value> - Criando um
Storage<std::string>com a entrada de string, imprimindo:String storage: <value> - Verificando se o armazenamento de string está vazio e imprimindo:
Is empty: <true/false>(imprimatrueoufalse) - Criando um
Pair<std::string, double>com os valores de string e double, depois chamandodisplay() - Criando um
Pair<int, int>com ambas as entradas inteiras, depois chamandodisplay()
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 diferentes tipos. 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.
Folha de consulta
Templates de classe permitem que você crie classes independentes de tipo. O compilador gera versões específicas para cada tipo que você utiliza.
Template de Classe Básico
template <typename T>
class Box {
T value;
public:
Box(T v) : value(v) {}
T getValue() const { return value; }
void setValue(T v) { value = v; }
};Ao criar objetos a partir de templates de classe, você deve especificar explicitamente o tipo usando colchetes angulares:
Box<int> intBox(42);
Box<std::string> strBox("Hello");Múltiplos Parâmetros de Tipo
Templates de classe podem ter múltiplos parâmetros de tipo:
template <typename T, typename U>
class Pair {
T first;
U second;
public:
Pair(T f, U s) : first(f), second(s) {}
};Parâmetros Não-Tipo
Templates também podem aceitar parâmetros que não são tipos, como inteiros:
template <typename T, int Size>
class FixedArray {
T data[Size];
public:
int size() const { return Size; }
};
FixedArray<double, 5> arr; // Array of 5 doublesDefinindo Funções Membro Fora da Classe
Ao definir funções membro fora da classe, repita 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; }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 entrada de string, imprimir: String storage: <value>
// TODO: Verificar se o armazenamento de string está vazio, imprimir: Is empty: true/false
// TODO: Criar Pair<std::string, double> com string e double, chamar display()
// TODO: Criar Pair<int, int> com ambos os inteiros, chamar display()
return 0;
}
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
1Fundamentos de OOP
Arquivos ExternosBuild e Compilação em C++Arquivos Header e SourceNamespaces e EscopoIntrodução a OOP em C++Classes vs ObjetosO Ponteiro 'this'Métodos (Funções Membro)Atributos (Membros de Dados)Básico de Ctors e DtorsRecapitulação - Calculadora Simples4Propriedades de Classe
Membros de Instância vs EstáticosGetters e SettersFunções de Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRecapitulação - Gerenciador de Conta Bancária7Herança
Herança BásicaNíveis de Acesso na HerançaOrdem de Chamada de Ctor e DtorSobrescrita de MétodosFunções Virtuais e VTableHerança MúltiplaHerança VirtualRecapitulação - Hierarquia de Funcionários2Gerenciamento de Memória
Memória Stack vs HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Smart Pointers em C++RAII em C++Recapitulação - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de Acesso em C++Especificadores de Acesso em DetalhesOcultação de InformaçãoStruct vs ClassClasses Aninhadas e InternasRecapitulação - Sistema de Registros de Alunos8Polimorfismo
Polimorfismo de Compilação vs Tempo de ExecuçãoSobrecarga de FunçõesFunções Virtuais RevisitadasFunções Virtuais PurasClasses AbstratasDesign de Interfaces em C++Dynamic Casting e RTTIRecapitulação - Calculadora de Formas3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentaçãoListas de Inicialização do ConstrutorConstrutores DelegadosMergulho Profundo em DestrutoresRegra dos Três / Cinco / ZeroRecapitulação - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de StreamSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçãoTemplates de ClasseEspecialização de TemplatesTemplates VariádicosFundamentos de SFINAE e Type TraitsRecapitulação - Container Genérico