2012-06-05 12 views
13

Il mio obiettivo è avere costanti globali in un gioco C++ su cui sto lavorando (per rappresentare alcune informazioni grafiche e simili). La mia attuale implementazione è di buttarli tutti in un file .h e includerli ovunque. Funziona, eccetto che ogni volta che cambio un'impostazione, l'intero codice base deve essere ricompilato.Corretta implementazione della configurazione globale

Quindi, la mia prossima idea era di lanciarli in qualche file di configurazione txt e analizzarli, in questo modo nessun codice viene effettivamente modificato quando le impostazioni cambiano. Il parser era abbastanza semplice e potevo inserire i valori nelle costanti, ma poiché il parser era un blocco di codice, le costanti non erano più globali.

C'è un buon modo per risolvere questo? Forse un modo per renderli globali pur essendo in un blocco o in qualche modo per evitare di ricompilare tutto quando si cambiano le impostazioni?

risposta

11

Un altro modo per farlo sarebbe quello di creare una classe singleton.

#include <fstream> 
#include <map> 
#include <string> 

class ConfigStore 
{ 
public: 
    static ConfigStore& get() 
    { 
     static ConfigStore instance; 
     return instance; 
    } 
    void parseFile(std::ifstream& inStream); 
    template<typename _T> 
    _T getValue(std::string key); 
private: 
    ConfigStore(){}; 
    ConfigStore(const ConfigStore&); 
    ConfigStore& operator=(const ConfigStore&); 
    std::map<std::string,std::string> storedConfig; 
}; 

Qui la configurazione viene salvata in una mappa, il che significa il più a lungo ParseFile in grado di leggere il file e getValue in grado di analizzare il tipo non v'è alcuna necessità di ricompilare la classe di configurazione se si aggiungono nuove chiavi.

Usage:

std::ifstream input("somefile.txt"); 
ConfigStore::get().parseFile(input); 
std::cout<<ConfigStore::get().getValue<std::string>(std::string("thing"))<<std::endl; 
+0

Certo, inizialmente volevo farlo senza costrutti aggiunti come questo, ma questo segue più convenzioni OO e funziona meglio in generale! Mi sono piaciuti anche i suggerimenti di Joachim, ma questo è quello che ha risolto per me, grazie! – akroy

+1

@akroy Mi permetto di non essere d'accordo. Che tipo di convenzioni OO intendi qui? Abbiamo un singleton. La soluzione di alcuni programmatori sembra nettamente superiore all'introduzione di un singleton fondamentalmente costruito attorno a 'std :: map' con una ricerca lenta e senza la sicurezza del tipo senza alcun vantaggio reale sulle variabili nude – IceFire

+0

Hey IceFire! Per il contesto, questa domanda è di 5 anni fa, quando stavo imparando a programmare. Guardando il thread dei commenti, sembra che io abbia preferito anche la soluzione di alcuni programmatori per il tizio in teoria, ma non è riuscita a superare il compilatore. Quindi, se ti ricompensa, più potere per te. :) – akroy

1

inserire solo le dichiarazioni nel file head e inserire le definizioni in un file cpp. poi cambi le definizioni nel file cpp non causerà la ricompilazione di tutto il codice

2

Che ne dici di creare funzioni che restituiscono le costanti che puoi specificare in un file .cxx? Per esempio:

// foo.h 
const int BAR(); 

// foo.cxx 
const int BAR() { 
    return 10; 
}; 
17

Il modo che ho usato risolvere questo è quello di mettere le variabili in un namespace globale a parte, che si trova in un file di intestazione con un nome simile config.h, quindi includere il file ovunque.

// In config.h 

#ifndef CONFIG_H 
#define CONFIG_H 

namespace config 
{ 
    extern int some_config_int; 
    extern std::string some_config_string; 

    bool load_config_file(); 
} 

#endif 

Il in un file di origine, si definisce la variabile e anche loro di impostare un valore predefinito. Questo file sorgente ha anche il codice per caricare le variabili dal tuo file di configurazione.

// In config.cpp 

namespace config 
{ 
    int some_config_int = 123; 
    std::string some_config_string = "foo"; 
} 

bool config::load_config_file() 
{ 
    // Code to load and set the configuration variables 
} 

Ora, in ogni file sorgente è necessario le variabili di configurazione, includono config.h e accedervi come config::some_config_int.

Tuttavia, non esiste un modo "corretto" per risolvere questo, tutti i modi in cui il lavoro è corretto ai miei occhi.

+0

Questa soluzione sembra davvero l'ideale, perché mi permette di caricare un file di configurazione, per cui un utente potrebbe modificare le impostazioni senza compilazione. Ma ho cercato di imitare esattamente la logica del codice che hai usato, e sto ricevendo "un riferimento indefinito a" config :: VARIABLE_NAME "" "ogni volta che viene utilizzata una variabile. Anche quando non ho usato alcuna funzione di caricamento e puramente definita le variabili nel file .cpp, ho ottenuto lo stesso errore. (Ho usato la stessa sintassi esatta con extern in .h e la dichiarazione e la definizione complete in .cpp) – akroy

+0

@Akroy Costruisci/link con il nuovo file sorgente? –

+0

Sì. Quindi, se config.h ha namespace config {extern int x;}, config.cpp ha namespace config {int x = 5;}, quindi in un altro file che contiene #include "config.h", dovrei essere in grado di accedere a config :: x? C'è qualcosa che mi manca? – akroy

Problemi correlati