Métodos e Variáveis Estáticos
Parte da seção Programação Orientada a Objetos do Journey de C++ da Coddy. Lição 31 de 104.
Você aprendeu que membros estáticos são compartilhados entre todos os objetos. Agora, vamos explorar como definir e usar corretamente métodos estáticos junto com variáveis estáticas.
Variáveis estáticas declaradas dentro de uma classe devem ser definidas fora da classe, normalmente em um arquivo-fonte. Isso ocorre porque membros estáticos precisam de exatamente um local de armazenamento compartilhado por todos os objetos:
class Counter {
static int count; // Apenas declaração
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { // Método estático
return count;
}
};
// Definição - necessária fora da classe
int Counter::count = 0;Um método estático pertence à classe, não a nenhum objeto. Isso tem uma consequência importante: métodos estáticos não podem acessar membros de instância nem usar o ponteiro this, porque não são chamados em nenhum objeto específico.
class MathUtils {
static double pi;
public:
static double circleArea(double radius) {
return pi * radius * radius; // Pode acessar membros estáticos
}
};
double MathUtils::pi = 3.14159;
// Chamado sem um objeto
double area = MathUtils::circleArea(5.0);Métodos estáticos são ideais para funções utilitárias que não precisam do estado de um objeto, métodos de fábrica que criam objetos ou para acessar dados estáticos. Como não exigem uma instância de objeto, você os chama usando o nome da classe e o operador de resolução de escopo: ClassName::methodName().
Desafio
FácilVamos criar um sistema gerador de IDs exclusivos que demonstra como métodos e variáveis estáticos trabalham juntos para fornecer funcionalidades no nível da classe sem precisar de instâncias de objetos.
Você criará dois arquivos para organizar seu código:
IDGenerator.h: defina uma classeIDGeneratorque gere IDs exclusivos sequenciais. Sua classe deve ter:- Um membro estático privado
nextIdque acompanha o próximo ID a ser atribuído (começa em1000) - Um membro estático privado
prefix(string) que armazena um prefixo personalizável para todos os IDs - Um método estático
setPrefix(const std::string& p)que altera o prefixo - Um método estático
getNextId()que retorna uma string combinando o prefixo e o número do ID atual e, em seguida, incrementanextIdpara a próxima chamada - Um método estático
peekNextId()que retorna qual seria o próximo ID sem incrementar o contador - Um método estático
getGeneratedCount()que retorna quantos IDs foram gerados (dica: calcule a partir do valor inicial e donextIdatual) - Um método estático
reset()que redefinenextIdpara1000
Lembre-se de definir seus membros estáticos fora da classe, após a definição da classe. Inicialize
prefixcom"ID-".- Um membro estático privado
main.cpp: demonstre a chamada de métodos estáticos usando o nome da classe sem criar nenhum objeto. Leia um prefixo personalizado da entrada e, em seguida:- Imprima
"Peek: <peeked_id>"usandopeekNextId() - Gere três IDs usando
getNextId()e imprima cada um como"Generated: <id>" - Imprima
"Count: <count>"mostrando quantos IDs foram gerados - Altere o prefixo usando o valor da entrada com
setPrefix() - Gere mais dois IDs e imprima cada um como
"Generated: <id>" - Imprima
"Count: <count>"novamente - Chame
reset() - Imprima
"After reset - Peek: <peeked_id>" - Imprima
"After reset - Count: <count>"
- Imprima
Observe que você nunca cria um objeto IDGenerator: todos os métodos são chamados diretamente na classe usando IDGenerator::methodName(). Essa é a principal característica dos métodos estáticos: eles pertencem à própria classe, não a nenhuma instância específica.
Inclua <string> e <iostream> no seu arquivo de cabeçalho e não se esqueça dos protetores de cabeçalho.
Experimente você mesmo
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// Ler o prefixo personalizado da entrada
string customPrefix;
cin >> customPrefix;
// TODO: Imprima "Peek: <peeked_id>" usando peekNextId()
// TODO: Gere três IDs usando getNextId() e imprima cada um como "Generated: <id>"
// TODO: Imprima "Count: <count>" mostrando quantos IDs foram gerados
// TODO: Altere o prefixo usando o valor de entrada com setPrefix()
// TODO: Gere mais dois IDs e imprima cada um como "Generated: <id>"
// TODO: Imprima "Count: <count>" novamente
// TODO: Chame reset()
// TODO: Print "After reset - Peek: <peeked_id>"
// TODO: Print "After reset - Count: <count>"
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 POO
Arquivos externosBuild e compilação em C++Arquivos de cabeçalho e arquivos-fonteNamespaces e escopoIntrodução à POO em C++Classes vs. objetosO ponteiro 'this'Métodos (funções membro)Atributos (membros de dados)Noções básicas de construtores e destruidoresRevisão - calculadora simples4Propriedades de Classe
Membros de Instância vs. EstáticosGetters e SettersFunções Membro ConstPalavra-chave MutableMétodos e Variáveis EstáticosFunções e Classes FriendRevisão - Gerenciador de Contas Bancárias7Herança
Herança básicaNíveis de acesso da herançaOrdem de chamada de construtor e destrutorSobrescrita de métodosFunções virtuais e VTableHerança múltiplaHerança virtualRevisão - Hierarquia de funcionários10Visão geral da STL
Visão geral e filosofia da STLContêineres da STLIteradoresAlgoritmos da STLFunctors e expressões lambdaRecapitulação - Frequência de palavras13Padrões de Projeto — Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonFactory e Abstract FactoryPadrão BuilderPadrão ObserverPadrão Strategy2Gerenciamento de Memória
Memória Stack vs. HeapPonteiros e ReferênciasMemória Dinâmica (new/delete)Ponteiros Inteligentes em C++RAII em C++Revisão - Gerenciador de Array Dinâmico5Encapsulamento
Especificadores de acesso em C++Especificadores de acesso em profundidadeOcultação de informaçõesStruct vs ClasseClasses aninhadas e internasRecapitulação - Sistema de registros de alunos8Polimorfismo
Polimorfismo em compilação vs. execuçãoSobrecarga de funçõesFunções virtuais revisadasFunções virtuais purasClasses abstratasDesign de interfaces em C++Conversão dinâmica e RTTIRecapitulação — Calculadora de formas11Conceitos Avançados de OOP
Composição vs. HerançaMixins via CRTPIdioma PimplApagamento de TiposClasses Enum e Tipagem ForteTratamento de Exceções em OOPHierarquias de Exceções Personalizadas14Padrões de Projeto — Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositeRAII como Padrão3Construtores e Destrutores
Construtor PadrãoConstrutor ParametrizadoConstrutor de CópiaConstrutor de MovimentoListas de Inicialização do ConstrutorConstrutores DelegantesAprofundamento em DestrutoresRegra dos Três / Cinco / ZeroRevisão - Classe String6Sobrecarga de Operadores
Introdução à Sobrecarga de OperadoresSobrecarga de Operadores AritméticosSobrecarga de Operadores de ComparaçãoOperadores de FluxoSobrecarga do Operador de AtribuiçãoSobrecarga dos Operadores [] e ()Operadores de Conversão de TipoRecapitulação - Classe Matrix9Templates
Templates de FunçõesTemplates de ClassesEspecialização de TemplatesTemplates VariádicosNoções Básicas de SFINAE e Traits de TiposRecapitulação - Contêiner GenéricoPratique por conta própria: Compilador de C++ online