Pergunta

Existe alguma maneira de adicionar um campo para uma classe em tempo de execução (um campo que não existia antes)? Algo como esse trecho:

Myobject *ob; // create an object
ob->addField("newField",44); // we add the field to the class and we assign an initial value to it
printf("%d",ob->newField); // now we can access that field

Eu realmente não me importo como ele seria feito, eu não me importo se é uma gambiarra ou não, eu gostaria de saber se isso poderia ser feito, e um pequeno exemplo, se possível.

Outro Exemplo: dizer que tenho um arquivo XML que descreve esta classe:

<class name="MyClass">
   <member name="field1" />
   <member name="field2" />
</class>

e eu quero "add" campos "field1" e "field2" para a classe (assumindo que a classe já existe). Vamos dizer que este é o código para a classe:

class MyClass {
};

Eu não quero criar uma classe em tempo de execução, eu só quero acrescentar membros / campos para um já existente.

Obrigado!

Foi útil?

Solução

Use um mapa e de uma variante.

Por exemplo, usando boost :: variant. Consulte http://www.boost.org/doc/libs/ 1_36_0 / doc / html / variant.html

(Mas é claro, você pode criar seu próprio, para atender os tipos de seus atributos XML.)

#include <map>
#include <boost/variant.hpp>

typedef boost::variant< int, std::string > MyValue ;
typedef std::map<std::string, MyValue> MyValueMap ;

Ao adicionar MyValueMap como um membro de sua classe, você pode adicionar propriedades de acordo com seus nomes. O que significa que o código:

oMyValueMap.insert(std::make_pair("newField", 44)) ;
oMyValueMap.insert(std::make_pair("newField2", "Hello World")) ;
std::cout << oMyValueMap["newField"] ;
std::cout << oMyValueMap["newField2"] ;

Ao encapsular em uma classe MyObject, e adicionando os acessores direito sobrecarregados nesta classe MyObject, o código acima torna-se um pouco mais clara:

oMyObject.addField("newField", 44) ;
oMyObject.addField("newField2", "Hello World") ;
std::cout << oMyObject["newField"] ;
std::cout << oMyObject["newField2"] ;

Mas você perde um pouco a segurança tipo de C ++ fazê-lo. Mas para XML, isso é inevitável, eu acho.

Outras dicas

Não há nenhuma maneira de fazê-lo da maneira que você descreveu, uma vez que as necessidades do compilador para resolver a referência em tempo de compilação -. Ele irá gerar um erro

Mas veja O Desenho Universal Padrão.

Você não pode fazer esse trabalho sintaxe (por causa de verificação estática em tempo de compilação), mas se você estiver disposto a modificar a sintaxe, você pode conseguir o mesmo efeito com bastante facilidade. Seria bastante fácil de ter um membro dicionário com um string-> mapeamento blob, e tem funções de membro como:

template< typename T > T get_member( string name );
template< typename T > void set_member( string name, T value );

Você poderia fazer a sintaxe mais compacta / complicado se você quiser (por exemplo: usando um '->' override operador). Existem também alguns truques específicos do compilador que você poderia possivelmente alavancagem (MSVC suportes __declspec (propriedade), por exemplo, que permite mapear referências a uma variável de membro para métodos de um formato específico). No final do dia, porém, você não vai ser capaz de fazer algo que o compilador não aceita na língua e obtê-lo para compilar.

Versão curta: Não é possível fazê-lo. Não há suporte nativo para isso, c ++ é digitado estaticamente e o compilador tem de conhecer a estrutura de cada objeto a ser manipulado.

Recomendação: Use um interperter incorporado. E não escrever o seu próprio (veja abaixo), obter um que já está trabalhando e depurado.


O que você pode fazer:. Implementar interperter apenas o suficiente para suas necessidades

Seria bastante simples de configurar a classe com um membro de dados como

std::vector<void*> extra_data;

para o qual você pode anexar dados arbitrários em tempo de execução. O custo deste é que você terá que gerenciar esses dados à mão com métodos como:

size_t add_data_link(void *p); // points to existing data, returns index
size_t add_data_copy(void *p, size_t s) // copies data (dispose at
                                        // destruction time!), returns 
                                        // index 
void* get_data(size_t i); //...

Mas isso não é o limite, com um pouco mais de cuidado, você pode associar os dados arbitrários com um nome e você pode continuar a elaborar este esquema, tanto quanto desejar (add digite info, etc ...), mas o que este vem para baixo é a implementação de um interperter para cuidar de sua flexibilidade de tempo de execução.

Não - C ++ não suporta qualquer manipulação do sistema de tipos como este. línguas, mesmo com algum grau de runtime reflexão (por exemplo, NET) não apoiaria exatamente este paradigma. Você precisaria de uma linguagem muito mais dinâmico para ser capaz de fazê-lo.

Eu estava olhando para isso e eu queria procurar um pouco ao redor, este fragmento de código obtido a partir de: Blog de Michael Hammer parece ser uma boa maneira de fazer isso, usando boost :: qualquer

Primeiro você definir uma estrutura que define uma std :: mapa que contém uma chave (ou seja, nome da variável) e o valor. A função é definida ao anúncio do par e configurá-lo juntamente com uma função para obter o valor. simples bastante se você me perguntar, mas parece uma boa maneira de começar antes de fazer coisas mais complexas.

struct AnyMap {
  void addAnyPair( const std::string& key , boost::any& value );

  template<typename T>
  T& get( const std::string key ) {
    return( boost::any_cast<T&>(map_[key]) );
  }

  std::map<const std::string, boost::any> map_;
};

void AnyMap::addAnyPair( const std::string& key , boost::any& value ) {
  map_.insert( std::make_pair( key, value ) );
}

fundo, este é um hack, já que C ++ é rigorosa linguagem de verificação de tipo e, portanto, mentira monstro dentro para aqueles que dobrar as regras.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top