Pergunta

Estou interessado em fazer algo como o seguinte para aderir a um padrão de projeto Objeto Nulo e evitar testes NULL prolíficos:

class Node;
Node* NullNode;

class Node {
public:
  Node(Node *l=NullNode, Node *r=NullNode) : left(l), right(r) {};
private:
  Node *left, *right;
};

NullNode = new Node();

Claro que, como está escrito, NullNode tem diferentes posições de memória antes e depois da declaração de classe Node. Você poderia fazer isso sem a declaração para a frente, se você não quer ter argumentos padrão (ou seja, remover Nó * r = NullNode).

Outra opção seria usar algum inheritence: fazer uma classe pai (Node) com duas crianças (NullNode e FullNode). Em seguida, o nó exemplo acima seria o código para FullNode e o NullNode no código acima seria de tipo NullNode herdar a partir do nó. Eu odeio resolver problemas simples por apelos para inheritence.

Assim, a pergunta é: como é que você aplicar padrões de objeto nulo para estruturas recursivas de dados (classes) com argumentos padrão (! Que são instâncias dessa mesma classe) em C ++

Foi útil?

Solução

Use extern:

extern Node* NullNode;
...
Node* NullNode = new Node();

Melhor ainda, torná-lo um membro estático:

class Node {
public:
  static Node* Null;
  Node(Node *l=Null, Node *r=Null) : left(l), right(r) {};
private:
  Node *left, *right;
};

Node* Node::Null = new Node();

Dito isto, tanto em código existente, e alterações acima, você vazar uma instância de Node. Você poderia usar auto_ptr, mas isso seria perigoso por causa do fim incerto de destruição de globals e estática (um destruidor de alguns podem precisar Node::Null global, e pode ou não ser já tinha ido até lá).

Outras dicas

Eu realmente implementado uma árvore recursiva (para JSON, etc.) fazendo algo parecido com isto. Basicamente, sua classe base torna-se a implementação "NULL", e sua interface é a união de todas as interfaces para o derivado. Você, então, ter derivado classes que implementam a peças-implementos "DataNode" dados getters e setters, etc.

Dessa forma, você pode programar para a interface de classe base e salvar um monte de dor. Você configura a implementação base para fazer toda a lógica clichê para você, por exemplo.

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

    virtual string OutputAsINI() const { return ""; }
};

class DataNode {
    private:
    string myName;
    string myData;

    public:
    DataNode(const string& name, const string& val);
    ~DataNode() {}

    string OutputAsINI() const { string out = myName + " = " + myData; return out; }
};

Desta forma, eu não tenho que teste nada- I cegamente chamar "OutputAsINI()". Lógica semelhante para toda a sua interface irá fazer a maioria dos testes nulos ir embora.

Inverter a hierarquia. Coloque o nó nulo na base:

class Node {
public:
  Node() {}
  virtual void visit() const {}
};

Em seguida, especializar-se necessário:

template<typename T>
class DataNode : public Node {
public:
  DataNode(T x, const Node* l=&Null, const Node* r=&Null)
    : left(l), right(r), data(x) {}

  virtual void visit() const {
    left->visit();
    std::cout << data << std::endl;
    right->visit();
  }

private:
  const Node *left, *right;
  T data;
  static const Node Null;
};

template<typename T>
const Node DataNode<T>::Null = Node();

Exemplo de uso:

int main()
{
  DataNode<char> a('A', new DataNode<char>('B'),
                        new DataNode<char>('C'));

  a.visit();

  return 0;
}

Output:

$ ./node 
B
A
C
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top