2013-06-20 9 views
5

I dati sono memorizzati in una struttura ad albero C++ che ho letto da un file. L'albero è simile al seguente:Combinazione di modelli ed ereditarietà nella conversione dell'albero

class BaseNode { 
    std::vector<BaseNode*> children_; 
    ... 
}; 
class WhiteNode : public BaseNode { ... }; 
class BlackNode : public BaseNode { ... }; 

Dopo che l'albero è stato creato, vorrei convertirlo, ad es. a una stringa.

Al fine di mantenere il codice albero separato dal codice di conversione, vorrei utilizzare i modelli, vale a dire l'attuazione qualcosa di simile:

template <class T> 
T WhiteNode::Convert() { ... }; 

Tuttavia, dal momento che i nodi della struttura vengono memorizzati come BaseNode*, io don sapere come accedere a una funzione membro del modello. E poiché le funzioni dei membri del modello non possono essere ereditate, non penso che funzionerà.

sono venuto su con una soluzione di lavoro, però:

class BaseConversion { 
public: 
    virtual ~BaseConversion() {} 
    virtual void * FromBlack() = 0; 
    virtual void * FromWhite() = 0; 
}; 

template <class T> 
class Conversion : public BaseConversion { 
public: 
    void * FromBlack(); 
    void * FromWhite(); 
}; 

class BaseNode { 
    std::vector<BaseNode*> children_; 
    virtual void * Convert(BaseConversion * conversion) = 0; 
public: 
    virtual ~BaseNode() {} 
    template <class T> 
    T Convert() { 
    return *static_cast<T*>(Convert(new Conversion<T>)); 
    } 
}; 

class WhiteNode : public BaseNode { 
    void * Convert(BaseConversion * conversion) { 
    return conversion->FromWhite(); 
    } 
}; 

class BlackNode : public BaseNode { 
    void * Convert(BaseConversion * conversion) { 
    return conversion->FromBlack(); 
    } 
}; 

E la logica di trasformazione può essere completamente separati:

template <> 
void * Conversion<std::string>::FromWhite() { 
    return new std::string("converting WHITE node to std::string ..."); 
} 

template <> 
void * Conversion<std::string>::FromBlack() { 
    return new std::string("converting BLACK node to std::string ..."); 
} 

Testing il codice:

BaseNode * node = new BlackNode; 
std::cout << node->Convert<std::string>() << std::endl; 
node = new WhiteNode; 
std::cout << node->Convert<std::string>() << std::endl; 

rendimenti il risultato atteso:

converting BLACK node to std::string ... 
converting WHITE node to std::string ... 

Sebbene questa soluzione funzioni, sono sicuro che può essere eseguita molto più facilmente. Qualsiasi altra soluzione più semplice che ho trovato fallita, ad es. a causa della cancellazione del tipo.

Apprezzerei qualsiasi aiuto in merito. Grazie!

risposta

2

Qualcosa di simile alla soluzione ma senza annullamento *.

class NodeVisitor 
{ 
    virtual void VisitBlack(BlackNode* node); 
    virtual void VisitWhite(BlackNode* node); 
}; 

class BaseNode { 
    std::vector<BaseNode*> children_; 
    ... 
    virtual void visit(NodeVisitor* visitor) = 0; 
}; 

class WhiteNode : public BaseNode { 
    virtual void visit(NodeVisitor* visitor) { visitor->visitWhite(this); } 
}; 

class BlackNode : public BaseNode { 
    virtual void visit(NodeVisitor* visitor) { visitor->visitBlack(this); } 
}; 

Poi

std::string convert(BaseNode* node) 
{ 
    class ConvertVisitor 
     : public NodeVisitor 
    { 
     ConvertVisitor(std::string* res) 
      : m_res(res) 
     { } 

     virtual void VisitBlack(BlackNode* node) 
     { 
      *m_res = // convert black node to string; 
     } 

     virtual void VisitWhite(BlackNode* node) 
     { 
      *m_res = // convert white node to string; 
     } 

     std::string* m_res; 
    }; 

    std::string res; 
    ConvertVisitor visitor(&res); 
    node->visit(&visitor); 
    return res; 
} 
+0

Grazie. Evitare il puntatore del vuoto potrebbe essere leggermente più elegante. Tuttavia, stavo cercando qualcosa di più compatto, forse senza conversioni o classi di visitatori. – DonDieselkopf

+0

Questo non sarà completamente fattibile. Hai il supporto per C++ 11? –

+0

Sì, sì. Se c'è una soluzione C++ 11, sarei curioso. In realtà mi aspettavo qualche soluzione simile a CRTP. Ma guardando la mia domanda, sono sempre più tentato di seguire il modello del visitatore. Tuttavia, qualsiasi altra opinione è molto gradita. – DonDieselkopf