Domanda

La mia domanda precedente su questo argomento è stato risposto e ho avuto alcuni test bel lavoro. Mappa funzioni di una classe

La mia domanda è ora, se c'è un modo per pur dichiarando la funzione, in grado di registrare in una mappa, come ho capito in questa domanda sugli spazi dei nomi e classi: In qualche modo registrare il mio classi in un elenco

gli spazi dei nomi e classi andava bene per registrare in una mappa utilizzando la parola chiave "statica", con questo, quei casi statici sarebbero costruite prima del main () essere chiamato.

Posso fare che in qualche modo con le funzioni di classe?
perché quando uso parola static all'interno di una dichiarazione di classe, non posso inizializzare il membro che posso fuori la dichiarazione di classe (come con namespace e classi nel secondo URL sopra)

Credo che avrei potuto hardcode tutti i membri all'interno del costruttore e registrarli in una mappa, ma vorrei sapere se c'è un modo per farlo, mentre dichiaro i membri, per rendere più facile in futuro

Grazie,
Joe

È stato utile?

Soluzione

Qual è il tuo problema?

Il problema è che, purtroppo, in funzioni C ++ non sono considerati i membri di prima classe.

Oh, certo ci sono quei puntatori a funzioni che funzionano abbastanza bene, ma non v'è nessun tipo di funzione generica o qualcosa di simile.

Non ci sono però modi per aggirare questo, il più semplice Penso che essere il modello Command.

Nel modello Command una funzione (funzionamento) viene astratta via in un oggetto. Gli argomenti vengono memorizzati nell'oggetto per un successivo riutilizzo (ad esempio undo o redo comando) e un'interfaccia unificata esiste per eseguire l'operazione stessa.

Meno chiacchiere, più codice:

class Command
{
public:
  virtual ~Command() {}

  virtual Command* clone() const = 0;

  virtual void execute() = 0;
};

Semplice?

class Foo {};

class FooCommand: public Command
{
public:
  void parameters(Foo& self, int a, std::string const& b);

  virtual FooCommand* clone() const;
  virtual void execute();

private:
  Foo* m_self;
  int m_a;
  std::string const* m_b;
};

Ora, la cosa dolce è che posso semplicemente memorizzare il mio comando in una mappa.

 // registration
 typedef boost::ptr_map<std::string, Command> commands_type;

 commands_type commands;
 commands.insert("foo", FooCommand());

 // get the command
 Foo foo;
 FooCommand* cFoo = dynamic_cast<FooCommand*>(commands["foo"].clone());
 if (cFoo != 0)
 {
   cFoo->parameters(foo, 2, "bar");
   cFoo->execute();
 }

Questa proposta avrebbe ancora bisogno di un po 'di lavoro.

  • passando i parametri è abbastanza fastidioso in quanto richiede un cast verso il basso.
  • I non riguardava me stesso con sicurezza rispetto alle eccezioni, ma restituisce un auto_ptr o un shared_ptr sarebbe meglio per il metodo clone ...
  • la distinzione tra un const e non const argomento Foo non è così facile per introdurre.

Tuttavia è più sicuro che usare un void* per memorizzare i puntatori di funzionare in voi mappare visto che hai il vantaggio di RTTI per verificare se il tipo è corretto.

D'altra parte, la stampa la raccolta di comandi legati ad un particolare oggetto è incredibilmente facile ora (se ne avete uno mappa per oggetto), è possibile anche trovare il modo di emulare l'effetto di metodi virtual ecc ...

Ma spero vi rendete conto che si è in realtà cercando di attuare riflessione, e non sarà facile ... buona fortuna!

Altri suggerimenti

È possibile utilizzare il preprocessore per consentire codice come il seguente:

#include <iostream>

#include "Registration.h"

class myclass {
  public:
  myclass() { HANDLE_REGISTRATION(); }

  private:
  static void reg1()  { std::cout << "reg1" << std::endl; }
  static void reg2()  { std::cout << "reg2" << std::endl; }
  static void unreg() { std::cout << "ERROR!" << std::endl; }

  BEGIN_REGISTRATION();
    REGISTER(reg1);
    REGISTER(reg2);
  END_REGISTRATION();
};

int main()
{
  myclass obj;
  obj.callAllRegistered();

  return 0;
}

Gli hack preprocessore brutti sono nascosti in Registration.h:

#ifndef INCLUDED_REGISTRATION_H
#define INCLUDED_REGISTRATION_H

#include <string>
#include <map>

#define BEGIN_REGISTRATION() \
  std::map<std::string, void(*)()> reg; \
  void register_static(const std::string& name, void(*f)()) \
  { \
    reg[name] = f; \
  } \
  void registerAll() {

#define REGISTER(name) register_static(#name, name)

#define HANDLE_REGISTRATION() registerAll()

#define END_REGISTRATION() \
  } \
  public: \
  void callAllRegistered() { \
    std::map<std::string,void(*)()>::const_iterator it; \
    for (it = reg.begin(); it != reg.end(); ++it) \
      it->second(); \
  } \
  private: \
  typedef int unusedblahblahblah___

#endif

Quello che state cercando è un principio chiamato Riflessione . Purtroppo, C / C ++ non fornisce questa funzionalità, ed attuando quest'ultima in C ++ oggetto potrebbe rivelarsi molto complicato (se è ancora possibile).

Se è necessaria questa funzionalità, vorrei suggerire guardando un altro linguaggio che supporta le funzioni di metaprogrammazione come questo. Fare questo cosa esatta è banale in alcune altre lingue. Ad esempio, in Ruby si potrebbe dire:

class Myclass
  def initialize
  end

  def a
  end

  def b
  end
end

x = Myclass.new
x.methods
=> ["inspect", "b", "clone", "taguri", "public_methods", "display", "instance_va
riable_defined?", "equal?", "freeze", "taguri=", "methods", "respond_to?", "dup"
, "instance_variables", "to_yaml_style", "__id__", "method", "eql?", "id", "sing
leton_methods", "send", "taint", "frozen?", "instance_variable_get", "__send__",
"instance_of?", "to_a", "type", "to_yaml_properties", "protected_methods", "obj
ect_id", "instance_eval", "==", "===", "instance_variable_set", "to_yaml", "kind
_of?", "extend", "to_s", "a", "hash", "class", "tainted?", "=~", "private_method
s", "nil?", "untaint", "is_a?"]

Questo elenco di tutte le funzioni membro (molti dei quali vengono automaticamente generato in questo caso) associati con l'oggetto. Lo stesso può essere fatto per le variabili di istanza, ecc molte altre lingue offrono questi tipi di caratteristiche.

Se questa funzione è fondamentale per quello che stai facendo, allora vi consiglio di riesaminare la vostra scelta di linguaggio di programmazione, come ti sembra di essere che vogliono lavorare su un livello più alto di C / C ++ sono in genere progettati per. Può essere possibile calzascarpe questo genere di cose in C ++ utilizzando qualche tipo di oggetto / modello generatore classe, ma non sarebbe banale scrivere o utilizzare le classi risultanti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top