Uno dei motivi principali per cui non implementare un insieme di funzioni di utilità come classe è il fatto che quando si tratta di avere una classe senza stato che fornisce solo funzioni, allora c'è molto poco senso nell'istanziare quella classe come tutte le istanze sono identiche. Non c'è alcun significato nella definizione di un tipo di tipo di dati perché i tipi di dati sono contratti relativi a ciò che rappresentano lo stato / i dati. Quando non ci sono stati o dati, non c'è nulla da rappresentare.
Molte volte non è così semplice però. Per fare un esempio (questo è qualcosa che vorresti in una vera classe autosufficiente), considera una situazione in cui hai una funzione get_time_delta()
e vuoi restituire il tempo trascorso dall'ultima chiamata di get_time_delta()
funzione - una situazione comune quando si calcola per esempio quanto tempo ci vuole per eseguire una funzione render_scene()
in un gioco. Dovresti memorizzare il tempo per la prima chiamata e il tempo per la seconda chiamata e sottrarre il primo dal secondo - ma senza stato questo è impossibile. Un modo per fare questo sarebbe implementare una classe e mantenere questo stato come variabili dei membri privati, ma se questa è una classe di utilità generica, quei dati temporali che sono rilevanti per get_time_delta()
viene esposto anche ad altre funzioni di utilità. Questo è male perché si desidera ridurre al minimo l'ambito delle variabili. Un buon modo per procedere è quello di avere i dati di temporizzazione interni locali alla funzione get_time_delta()
specificandola con static
specificatori di classe di memoria.
Allo stato attuale, nell'esempio sopra citato, non abbiamo bisogno dello stato per la classe. Quindi, perché abbiamo bisogno di una classe per cominciare? Supponiamo di avere un'API come questa:
unsigned int delta_time = Util::get_time_delta();
Sarebbe irragionevole dover creare un'istanza di Util
in quanto non contiene nessuno stato. Pertanto dichiariamo get_time_delta()
come static
funzioni della classe o dichiariamo get_time_delta()
all'interno di uno spazio dei nomi Util
.
Tutto ciò detto, "il modo C ++" (qualunque cosa significhi, non leggerlo troppo) è definire funzioni di utilità all'interno di uno spazio dei nomi invece che come% funzioni membro membro di una classe di utilità.
In altre lingue, in particolare in C # e Java, esiste un pattern chiamato modello di utilità che simula spazi dei nomi - posizionando funzioni di utilità dietro a un "namespace" dichiarandoli come funzioni membro statiche di una classe. In C ++ questo non è affatto necessario a causa degli spazi dei nomi incorporati e delle funzioni indipendenti.