Objecto Padrão nulo, recursiva Class, e enviará a sua declaração
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 ++
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