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 adequadamente 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, geralmente em um arquivo de origem. 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 ou usar o ponteiro this, porque eles 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 do objeto, métodos de fábrica que criam objetos ou para acessar dados estáticos. Como eles 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 construir um sistema gerador de IDs únicos que demonstra como métodos e variáveis estáticas trabalham juntos para fornecer funcionalidade em nível de classe sem a necessidade de instâncias de objetos.
Você criará dois arquivos para organizar seu código:
IDGenerator.h: Defina uma classeIDGeneratorque gera IDs únicos sequenciais. Sua classe deve ter:- Um membro estático privado
nextIdque rastreia 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 então 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 redefinenextIdde volta para1000
Lembre-se de definir seus membros estáticos fora da classe após a definição da classe. Inicialize
prefixcomo"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 de 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(). Esta é a característica fundamental dos métodos estáticos: eles pertencem à própria classe, não a nenhuma instância específica.
Inclua <string> e <iostream> em seu arquivo de cabeçalho e não se esqueça dos "header guards".
Folha de consulta
Variáveis estáticas declaradas dentro de uma classe devem ser definidas fora da classe. 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++; }
static int getCount() {
return count;
}
};
// Definição - necessária fora da classe
int Counter::count = 0;Um método estático pertence à classe, não a qualquer objeto. Métodos estáticos não podem acessar membros de instância ou 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 usando o nome da classe
double area = MathUtils::circleArea(5.0);Métodos estáticos são chamados usando o nome da classe e o operador de resolução de escopo: ClassName::methodName(). Eles são ideais para funções utilitárias que não precisam do estado do objeto, métodos de fábrica ou acesso a dados estáticos.
Experimente você mesmo
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// Lê 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: Imprima "After reset - Peek: <peeked_id>"
// TODO: Imprima "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 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