2012-11-02 16 views
9

Sto imparando C++ eseguendo una piccola simulazione di robot e sto avendo problemi con le funzioni membro statiche all'interno delle classi.Funzioni e variabili membro statico C++

ho la mia classe Ambiente definita in questo modo:

class Environment { 
    private: 
     int numOfRobots; 
     int numOfObstacles; 

     static void display(); // Displays all initialized objects on the screen 

    public: 
     Robot *robots; 
     Obstacle *obstacles; 

     // constructor 
     Environment(); 

     static void processKeySpecialUp(int, int, int); // Processes the keyboard events 
}; 

Poi nel costruttore ho inizializzare i robot e gli ostacoli in questo modo:

numOfRobots = 1; // How many robots to draw 
numOfObstacles = 1; 
robots = new Robot[numOfRobots]; 
obstacles = new Obstacle[numOfObstacles]; 

Ecco esempio di funzione statica che utilizza tali variabili :

void Environment::display(void) { 
    // Draw all robots 
    for (int i=0; i<numOfRobots; i++) { 
     robots[i].draw(); 
    } 
} 

Quando provo a compilare, ottengo messaggi di errore come

error: invalid use of member ‘Environment::robots’ in static member function 

Ho provato a fare numOfRobots, numOfObstacles, robot e gli ostacoli statica, ma poi mi sono errori come

error: undefined reference to 'Environment::numOfRobots' 

Io apprezzo molto di qualcuno potrebbe spiegare a me quello che sto facendo male. Grazie!

+0

Nella versione statica del codice non si riesce a definire 'Ambiente :: numOfRobots', l'ha solo dichiarato. Aggiungi 'int Environment :: numOfRobots = 1;' a uno dei tuoi file sorgente. Un libro su C++ spiegherà come dichiarare e definire le variabili insieme a molte altre informazioni essenziali. – john

+1

Dato che hai detto che stai imparando C++, potrei suggerire di usare la libreria standard? Specificamente un 'std :: vector' invece di matrici raw. – bitmask

risposta

12

I metodi statici non possono utilizzare variabili non statiche della sua classe.

Questo perché un metodo statico può essere chiamato come Environment::display() senza un'istanza di classe, che rende qualsiasi variabile non statica utilizzata al suo interno, irregolare, cioè non ha un oggetto padre.

È necessario considerare il motivo per cui si sta tentando di utilizzare un membro statico per questo scopo. In sostanza, un esempio di come un metodo statico può essere utilizzato sia come tale:

class Environment 
{ 
private: 
    static int maxRobots; 
public: 
    static void setMaxRobots(int max) 
    { 
     maxRobots = max; 
    } 
    void printMaxRobots(); 
}; 

void Environment::printMaxRobots() 
{ 
    std::cout << maxRobots; 
} 

e si dovrebbe inizializzare sulla portata globale delle variabili, come:

int Environment::maxRobots = 0; 

Poi, all'interno main per esempio, è possibile utilizzare:

Environment::setMaxRobots(5); 

Environment *env = new Environment; 
env->printMaxRobots(); 
delete env; 
+0

Hai un'idea di come può essere risolto? Ho provato a rendere statiche queste variabili, ma stavo ricevendo errori (per favore, vedi la seconda parte della mia domanda) ... –

+1

Devi inizializzare le variabili statiche, vedi [Funzioni membro statico] (http: //publib.boulder. ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr039.htm). –

1

Una funzione membro statico è una funzione che può essere chiamata senza un oggetto reale di quel tipo. Tuttavia, la funzione Environment::display utilizza le variabili numOfRobots e robots, che risiedono entrambe in una particolare istanza della classe Environment. O rendere display non statico (perché vuoi che sia statico?) O rendere i membri statici di robot di Environment troppo.

Nel tuo caso, non vedo un motivo per rendere display o processKeySpecialUpstatic, quindi basta renderli normali funzioni membro. Se ti chiedi quando una funzione membro dovrebbe essere static, considera se quella funzione avrebbe senso se non sono stati creati oggetti di quella classe (cioè non è stato chiamato alcun costruttore). Se la funzione non ha senso in questo contesto, non dovrebbe essere static.

+0

Sto usando la libreria Glut per gestire la grafica e ho bisogno di mantenere il display statico. E come ho detto prima, ho provato a rendere statiche quelle variabili, ma stavo ricevendo errore: riferimento indefinito a 'Ambiente :: numOfRobots' –

0

Un metodo statico non può accedere alle variabili di istanza. Se si desidera accedere alla variabile di istanza, rimuovere la static dal metodo. Se tali valori possono essere uguali per tutte le istanze di robot, quindi renderli variabili statiche e il metodo può rimanere statico.

2

static membri sono quelli che li utilizzano non richiedono di istanze, in modo da non avere this, dal momento che richiedono this esemplificazione:

class foo { 
public 
    void test() { 
     n = 10; // this is actually this->n = 10 
    } 
    static void static_test() { 
     n = 10; // error, since we don't have a this in static function 
    } 
private: 
    int n; 
}; 

Come si vede non si può chiamare una funzione di istanza o utilizzare un'istanza membro all'interno di una funzione static. Quindi una funzione dovrebbe essere statica se la sua operazione non dipende dall'istanza e se si richiede un'azione nella vostra funzione che richiede this, è necessario pensare perché io chiamo questa funzione static mentre richiede this.

una variabile membro è static se dovesse condivisa tra tutte le istanze di un class e non appartiene a nessuna specifica class esempio, per esempio io può decidere di avere un contatore di istanze create della mia classe:

// with_counter.h 
class with_counter { 
private: 
    static int counter; // This is just declaration of my variable 
public: 
    with_counter() {++counter;} 
    ~with_counter() {--counter;} 

    static int alive_instances() { 
     // this action require no instance, so it can be static 
     return counter; 
    } 
}; 

// with_counter.cpp 
int with_counter::counter = 0; // instantiate static member and initialize it here 
3

Ci sono 2 problemi qui - l'algoritmo che stai cercando di implementare e il meccanismo del perché non verrà compilato.

Perché non viene compilato.

Stai mescolando variabili statiche e istanze/metodi - che va bene. Ma non è possibile fare riferimento a una variabile di istanza da un metodo statico. Questo è l'errore "uso non valido". Se ci pensi, ha senso. Esiste solo un metodo "static void display()". Quindi, se prova a fare riferimento alla variabile non statica (istanza) "robot", a quale si riferisce? Ci potrebbe essere 10 ... o nessuno.

La logica che si sta tentando di implementare.

Sembra che si desideri una singola classe Ambiente che gestisca N robot. È perfettamente logico. Un approccio comune consiste nel rendere Environment un "singleton", una variabile di istanza che consente solo una singola istanza. Quindi potrebbe allocare tutti i robot che desidera e fare riferimento ad essi liberamente perché non ci sono variabili/metodi statici.

Un altro approccio è quello di andare avanti e rendere l'intera classe Ambiente statica. Quindi mantieni un elenco (statico) di robot. Ma penso che la maggior parte delle persone in questi giorni direbbe che l'opzione numero 1 è la strada da percorrere.

+0

Grazie! Come posso rendere l'ambiente un singleton? Mai sentito parlare di questo ... –

+0

@ user1739770 Questa semplice risposta è che hai un metodo statico che restituisce un puntatore alla tua classe; se non ce n'è uno, lo crea e lo restituisce, altrimenti restituisce un puntatore a quello esistente. In questo modo hai una classe di 'istanza', ma non ne ottieni mai più di una copia. In pratica diventa piuttosto appiccicoso: vedi http://stackoverflow.com/questions/1008019/c-singleton-design-pattern. –

2

Il primo errore indica che non è possibile utilizzare membri non statici nelle funzioni membro statiche.

La seconda dice che è necessario definire membri statici, oltre a dichiarandoli È necessario definire le variabili membro statiche di fuori di una classe, in un file sorgente (non nell'intestazione) in questo modo:

int Environment::numOfRobots = 0; 

Non è necessario alcun membro statico. Per avere un'interfaccia GLUT assolutamente corretta e portatile, avere un oggetto a livello di file di tipo Environment e una funzione a livello di file (non membro) dichiarata con collegamento C. Per comodità, ha anche una funzione membro denominata display.

class Environment 
{ 
public: 
    void display() { ... } 
    ... 
}; 

static Environment env; 
extern "C" void display() { env.display(); } 
Problemi correlati