Metodi e variabili statici
Fa parte della sezione Programmazione orientata agli oggetti del percorso C++ di Coddy. Lezione 31 di 104.
Hai imparato che i membri statici sono condivisi tra tutti gli oggetti. Ora esploriamo come definire e usare correttamente i metodi statici insieme alle variabili statiche.
Le variabili statiche dichiarate all'interno di una classe devono essere definite all'esterno della classe, in genere in un file sorgente. Questo perché i membri statici necessitano di una sola posizione di memoria condivisa da tutti gli oggetti:
class Counter {
static int count; // Solo dichiarazione
public:
Counter() { count++; }
~Counter() { count--; }
static int getCount() { // Metodo statico
return count;
}
};
// Definizione - necessaria all'esterno della classe
int Counter::count = 0;Un metodo statico appartiene alla classe, non a un oggetto. Questo ha una conseguenza importante: i metodi statici non possono accedere ai membri di istanza né usare il puntatore this, perché non vengono chiamati su un oggetto specifico.
class MathUtils {
static double pi;
public:
static double circleArea(double radius) {
return pi * radius * radius; // Può accedere ai membri statici
}
};
double MathUtils::pi = 3.14159;
// Chiamato senza un oggetto
double area = MathUtils::circleArea(5.0);I metodi statici sono ideali per le funzioni di utilità che non hanno bisogno dello stato di un oggetto, per i metodi factory che creano oggetti o per accedere ai dati statici. Poiché non richiedono un'istanza di un oggetto, li chiami usando il nome della classe e l'operatore di risoluzione dell'ambito: ClassName::methodName().
Sfida
FacileCreiamo un sistema di generazione di ID univoci che dimostri come i metodi e le variabili statici lavorino insieme per fornire funzionalità a livello di classe senza dover creare istanze di oggetti.
Creerai due file per organizzare il codice:
IDGenerator.h: Definisci una classeIDGeneratorche genera ID univoci sequenziali. La classe deve avere:- Un membro statico privato
nextIdche tiene traccia del prossimo ID da assegnare (inizia da1000) - Un membro statico privato
prefix(stringa) che memorizza un prefisso personalizzabile per tutti gli ID - Un metodo statico
setPrefix(const std::string& p)che modifica il prefisso - Un metodo statico
getNextId()che restituisce una stringa che combina il prefisso e il numero dell'ID corrente, quindi incrementanextIdper la chiamata successiva - Un metodo statico
peekNextId()che restituisce quello che sarebbe il prossimo ID senza incrementare il contatore - Un metodo statico
getGeneratedCount()che restituisce quanti ID sono stati generati (suggerimento: calcola la differenza tra il valore iniziale e il valore corrente dinextId) - Un metodo statico
reset()che reimpostanextIda1000
Ricordati di definire i membri statici fuori dalla classe, dopo la definizione della classe. Inizializza
prefixa"ID-".- Un membro statico privato
main.cpp: Dimostra come chiamare i metodi statici usando il nome della classe senza creare oggetti. Leggi un prefisso personalizzato dall'input, poi:- Stampa
"Peek: <peeked_id>"usandopeekNextId() - Genera tre ID usando
getNextId()e stampa ciascuno nel formato"Generated: <id>" - Stampa
"Count: <count>"mostrando quanti ID sono stati generati - Modifica il prefisso usando il valore di input con
setPrefix() - Genera altri due ID e stampa ciascuno nel formato
"Generated: <id>" - Stampa di nuovo
"Count: <count>" - Chiama
reset() - Stampa
"After reset - Peek: <peeked_id>" - Stampa
"After reset - Count: <count>"
- Stampa
Nota che non crei mai un oggetto IDGenerator: tutti i metodi vengono chiamati direttamente sulla classe usando IDGenerator::methodName(). Questa è la caratteristica fondamentale dei metodi statici: appartengono alla classe stessa, non a una particolare istanza.
Includi <string> e <iostream> nel file header e non dimenticare le protezioni dell'header.
Provalo tu
#include <iostream>
#include <string>
#include "IDGenerator.h"
using namespace std;
int main() {
// Leggi il prefisso personalizzato dall'input
string customPrefix;
cin >> customPrefix;
// TODO: Stampa "Peek: <peeked_id>" usando peekNextId()
// TODO: Genera tre ID usando getNextId() e stampa ciascuno come "Generated: <id>"
// TODO: Stampa "Count: <count>" per mostrare quanti ID sono stati generati
// TODO: Cambia il prefisso usando il valore di input con setPrefix()
// TODO: Genera altri due ID e stampa ciascuno come "Generated: <id>"
// TODO: Stampa di nuovo "Count: <count>"
// TODO: Chiama reset()
// TODO: Stampa "After reset - Peek: <peeked_id>"
// TODO: Stampa "After reset - Count: <count>"
return 0;
}
Questa lezione include un breve quiz. Inizia la lezione per rispondere e tenere traccia dei tuoi progressi.
Tutte le lezioni di Programmazione orientata agli oggetti
1Fondamenti della programmazione orientata agli oggetti
File esterniBuild e compilazione in C++File header e file sorgenteNamespace e ambitoIntroduzione alla programmazione orientata agli oggetti in C++Classi e oggetti a confrontoIl puntatore 'this'Metodi (funzioni membro)Attributi (membri dati)Fondamenti di costruttori e distruttoriRiepilogo - Calcolatrice semplice4Proprietà delle classi
Membri di istanza e staticiGetter e setterFunzioni membro constParola chiave mutableMetodi e variabili staticiFunzioni e classi friendRiepilogo - Gestore di conti bancari7Ereditarietà
Ereditarietà di baseLivelli di accesso nell’ereditarietàOrdine di chiamata di costruttori e distruttoriRidefinizione dei metodiFunzioni virtuali e VTableEreditarietà multiplaEreditarietà virtualeRiepilogo - Gerarchia dei dipendenti2Gestione della memoria
Memoria Stack vs HeapPuntatori e riferimentiMemoria dinamica (new/delete)Puntatori intelligenti in C++RAII in C++Riepilogo - Gestore di array dinamico5Incapsulamento
Specificatori di accesso in C++Specificatori di accesso in dettaglioOccultamento delle informazioniStruct vs classClassi annidate e interneRiepilogo - Sistema di registrazione degli studenti8Polimorfismo
Polimorfismo a compile time e a runtimeOverload delle funzioniFunzioni virtuali: ripassoFunzioni virtuali pureClassi astratteProgettazione delle interfacce in C++Dynamic casting e RTTIRipasso: calcolatrice di forme11Concetti avanzati di OOP
Composizione vs ereditarietàMixin tramite CRTPIdiom PimplType ErasureEnum class e tipizzazione forteGestione delle eccezioni in OOPGerarchie personalizzate di eccezioni14Pattern di progettazione - Parte 2
Pattern CommandPattern AdapterPattern DecoratorPattern Template MethodPattern StatePattern CompositeRAII come pattern3Costruttori e distruttori
Costruttore predefinitoCostruttore con parametriCostruttore di copiaCostruttore di spostamentoListe di inizializzazione dei costruttoriCostruttori delegantiApprofondimento sui distruttoriRegola del Tre / Cinque / ZeroRipasso - classe String6Sovraccarico degli operatori
Introduzione al sovraccarico degli operatoriSovraccarico degli operatori aritmeticiSovraccarico degli operatori di confrontoOperatori di flussoSovraccarico dell'operatore di assegnazioneSovraccarico degli operatori [] e ()Operatori di conversione di tipoRipasso - Classe Matrix9Template
Template di funzioneTemplate di classeSpecializzazione dei templateTemplate variadiciBasi di SFINAE e dei trait di tipoRiepilogo - Contenitore genericoEsercitati da solo: Compilatore C++ online