2010-11-19 11 views
1

Je suis en train de créer un "système" pour pouvoir ensuite écrire dans un environnement "basé sur l'action". Ce que je veux, c'est donner à mon instance (c.-à-d. Une «voiture») un certain état (par exemple, stationner, conduire, démarrer). Ensuite, au cours d'un événement, il devrait exécuter le code en fonction de l'état.Transformer un membre de classe normal en un membre de classe statique

Je ne veux pas utiliser une instruction switch/if-then-else car cela est très errorprone & difficile à étendre. (Pour permettre plus d'états). Au lieu de cela, je veux utiliser des pointeurs de fonction.

Le code que j'ai (ignorer le sillyness des fonctions, ils doivent démontrer):

#define CALL_MEMBER_FN(object,ptrToMember) ((object).*(ptrToMember)) 
enum State {Set, Add, Mul}; 
class car { 
public: 
    typedef void (car::*MemFn)(int v); 
    car(int v, State _s) : val(v), s(_s) { 
     posFunctions.insert(std::make_pair(State(Set),&car::SetVal)); 
     posFunctions.insert(std::make_pair(State(Add),&car::AddVal)); 
    } 
    void DoIt(int v) { 
     //MemFn t = &car::SetVal; 
     MemFn t = posFunctions.find(s)->second; 
     CALL_MEMBER_FN(*this,t)(v); 
    } 
    int val; 
    State s; 
protected: 
    std::map<State,car::MemFn> posFunctions; 
    void SetVal(int v) { 
     val = v; 
    } 
    void AddVal(int v) { 
     val += v; 
    } 
    void MulVal(int v) { 
     val *= v; 
    } 
}; 

cela fonctionne comme je l'attends. (Je peux appeler créer un objet voiture, lui donner un certain état et ensuite appeler "doit - qui serait la fonction déclenchée par l'événement" pour effectuer les actions).

Cependant, il y a 1 chose très ennuyante: je dois créer la carte de fonction (qui mappe les états avec les fonctions à effectuer) pour chaque objet voiture indépendamment. Ce n'est pas vraiment "en réalité" (en réalité chaque voiture effectue toujours la même chose lorsque l'état est le même) et donc sujet à erreur/laid.

J'ai essayé de faire de "posFunctions" une carte statique et d'utiliser une fonction d'initialisation statique pour les 2 lignes du constructeur.

main.obj: erreur LNK2001: symbole externe non résolu "protégé: classe statique std :: carte, classe std :: allocateur>> :: voiture posFunctions"? (@ Voiture de posFunctions @@ 1V carte $ @ W4State @@ P8car @@ AEXH @ ZU? $ Less @ W4State @@@ std @@ V? $ Allocateur @ U? $ Paire @ $$ CBW4State @@ P8car @@ AEXH @ Z @ std @@@ 4 @@ std @@ A) Je suppose que c'est parce que j'accède à une fonction membre non statique - même si elle est pointée?

Est-il possible de rendre la carte statique (ou globale)?

Nous vous remercions de l'aide, paul23

+0

Votre erreur de lien de côté (que d'autres ont déjà répondu ci-dessous), avez-vous envisagé d'utiliser le modèle d'état pour modéliser cela? Pourrait faire pour une mise en œuvre plus propre. http://en.wikipedia.org/wiki/State_pattern – razlebe

+0

Merci à tous pour les réponses, j'ai vraiment besoin d'être plus prudent avec ces choses. – paul23

+0

Utilisez std :: function ou boost :: function si votre compilateur ne l'a pas. –

Répondre

1

Cela est possible - vous devez définir la variable statique 1 place (le fichier RPC pour cette classe la plus probable).

std::map<State,car::MemFn> car::posFunctions; 

Qu'est-ce que vous avez dans le fichier d'en-tête est juste une déclaration .

Ceci est analogue à la façon dont vous devez fournir une fonction définition dans le fichier .cpp pour chaque fonction que vous déclariez dans l'en-tête. Si vous manquez un des corps de la fonction, l'éditeur de liens vous donnera la même erreur sur chaque fonction manquante.

Pour initialiser cette structure à la demande, fournissez une fonction membre statique qui est appelée depuis votre constructeur de classe mais vérifie (de manière thread-safe si nécessaire) si elle a déjà été appelée.

void car::initFunctions() 
{ 
    static bool done(false); 
    if (done) 
    return; 

    // first pass, set up the map 
    done = true; 
} 
3

Tant que vous déclarez votre map statique, vous devez ajouter la ligne suivante dans votre fichier de mise en œuvre:

std::map<State,car::MemFn> car::posFunctions;

Voici un lien vers l'élément C++ FAQ concerné.

+0

cela vient de résoudre une erreur de compilation ennuyeuse pour moi, +1 merci – Freddie

2

Vous avez oublié de définir la carte sur une portée globale, à savoir

std::map<State,car::MemFn> car::posFunctions;

dans le fichier .cpp où vous définissez la voiture. Généralement cependant, quand vous faites une construction comme celle-ci, demandez-vous - pourriez-vous faire cela en utilisant le polymorphisme à la place?

Questions connexes