Pergunta

Eu escrevi um analisador de arquivo para um jogo que eu estou escrevendo para tornar mais fácil para mim para mudar vários aspectos do jogo (coisas como os dados de caracteres / estágio / colisão). Por exemplo, eu poderia ter uma classe de caracteres como este:

class Character
{
public:
    int x, y; // Character's location
    Character* teammate;
}

Eu configurar meu analisador de ler a partir de um arquivo de estrutura de dados com sintaxe semelhante a C ++

Character Sidekick
{
    X = 12
    Y = 0
}

Character AwesomeDude
{
    X = 10
    Y = 50
    Teammate = Sidekick
}

Isto irá criar duas estruturas de dados e colocá-los em um map<std::string, Character*>, onde a string chave é o nome que eu dei-lhe (neste caso Sidekick e AwesomeDude). Quando meu parser vê um ponteiro para uma classe, como o ponteiro do companheiro de equipe, é inteligente o suficiente para olhar para cima no mapa para buscar o ponteiro para essa estrutura de dados. O problema é que eu não posso declarar o companheiro de Sidekick para ser AwesomeDude porque não foi colocado no Mapa Ambiente ainda.

Estou tentando encontrar a melhor maneira de resolver isso para que eu possa ter meus objetos de referência estruturas de dados que ainda não foram adicionadas ao mapa. As duas soluções mais fáceis que eu posso pensar são: (a) adicionar a capacidade de estruturas de dados de declaração para a frente ou (b) tem o analisador ler o arquivo duas vezes, uma para preencher o mapa com ponteiros para estruturas de dados vazios e uma segunda vez para passar e preenchê-los.

O problema com (a) é que eu também pode decidir qual construtor chamar em uma classe, e se eu frente declarar algo que eu teria que ter o construtor ser separado do restante dos dados, o que pode ser confuso . O problema com (b) é que eu poderia querer declarar Sidekick e AwesomeDude em seus próprios arquivos. Eu tenho que fazer o meu analisador de ser capaz de tomar uma lista de arquivos para ler em vez de apenas um de cada vez (isto não é tão ruim eu acho, embora às vezes eu pode querer obter uma lista de arquivos para ler a partir de um Arquivo). (B) também tem a desvantagem de não ser capaz de usar estruturas de dados declarou mais tarde no próprio construtor, mas eu não acho que é um grande negócio.

Que maneira soa como uma abordagem melhor? Existe uma terceira opção que eu não tenha pensado? Parece que deve haver alguma solução inteligente para isso com referências ponteiro ou ligação ou algo assim ...: - / Acho que isso é um pouco subjetivo com base no que dispõe Eu quero me dar, mas qualquer entrada é bem-vinda.

Foi útil?

Solução

Quando você encontrar a referência pela primeira vez, simplesmente armazená-lo como uma referência. Em seguida, você pode colocar o personagem, ou a referência, ou o que quer em uma lista de "referências que precisam ser resolvidos mais tarde".

Quando o arquivo é feito, executado através aqueles que têm referências e resolvê-los.

Outras dicas

Bem, você pediu uma terceira opção. Você não tem que usar XML, mas se você seguir a seguinte estrutura, seria muito simples de usar um analisador SAX para construir sua estrutura de dados.

De qualquer forma, em vez de fazer referência a um companheiro de equipe, cada personagem referências a equipe (equipe azul neste caso). Isto irá dissociar a questão de referência circular. Apenas certifique-se de listar as equipes antes dos caracteres.

<team>Blue</team>

<character>
    <name>Sidekick</name>
    <X>12</X>
    <Y>0</Y>
    <teamref>Blue</teamref>
</character>

<character>
    <name>Sidekick</name>
    <X>10</X>
    <Y>50</Y>
    <teamref>Blue</teamref>
</character>

Pessoalmente, eu iria com b). Dividir seu código em classes Parser e Validador, tanto operacional na mesma estrutura de dados. O analisador irá ler e analisar um arquivo, enchendo a estrutura de dados e armazenamento de quaisquer referências a objetos como seus nomes textuais, deixando o nulo ponteiro real em sua estrutura para agora.

Quando você está carregamento terminado os arquivos, use a classe Validator para validar e resolver quaisquer referências, preenchendo os ponteiros "reais". Você vai querer considerar como estruturar seus dados para fazer essas pesquisas agradável e rápido.

Will disse exatamente o que eu estava prestes a escrever. Basta manter uma lista ou algo com as referências não resolvidos.

E não se esqueça de lançar um erro se houver referências não resolvidos uma vez que você terminar de ler o arquivo = P

Em vez de armazenar objeto de caracteres em seu mapa, armazenar um proxy para Character. O proxy do que contêm um apontador para o objecto de caracteres real quando o objecto é carregado. O tipo de caracteres :: companheiro de equipe será alterado para este tipo de proxy. Quando você lê em uma referência que já não está em seu mapa, você cria um proxy e usar o proxy. Quando você carregar um personagem que você já tem um proxy vazio no mapa, preenchê-lo com o seu personagem recém-carregado. Você também pode querer adicionar um contador para manter o controle de quantas procuração vazio que você tem no mapa para que você saiba quando todos os caracteres referenciados foram carregados.

Outra camada de engano .... sempre tornar a programação mais fácil e mais lento.

Uma opção seria para reverter a obrigação. O Mapa é responsável por preencher na referência

template<T> class SymbolMap // I never could rememeber C++ template syntax
{
   ...

   /// fill in target with thing name
   /// if no name yet, add it to the list of thing that will be name
   void Set(T& target, std::string name);

   /// define name as target
   /// go back and fill in anything that needs to be name
   void Define(T target, std::string name);

   /// make sure everything is resolved
   ~SymbolMap()
}

que se não interagem bem com valor / movendo semântica, mas eu suspeito que não muito vontade.

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