2013-06-20 9 views
5

Mam dane przechowywane w strukturze drzewa C++, które odczytałem z pliku. Drzewo wygląda następująco:Łączenie szablonów i dziedziczenia w konwersji drzewa

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

Po zbudowaniu drzewa chciałbym go przekonwertować, np. na ciąg.

W celu utrzymania kodu drzewo odrębną od kodu konwersji, chciałbym używać szablonów, czyli wdrażaniu coś takiego:

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

Jednakże, ponieważ węzły drzewa są przechowywane jako BaseNode*, I don nie wiem, jak uzyskać dostęp do takiej funkcji członka szablonu. A ponieważ funkcje członków szablonu nie mogą zostać odziedziczone, nie sądzę, aby to działało.

zrobiłem pochodzić z roztworu roboczego, ale:

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(); 
    } 
}; 

a logiką transformacji mogą być całkowicie oddzielone: ​​

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 ..."); 
} 

Testowanie kodu:

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

powraca oczekiwany wynik:

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

Chociaż to rozwiązanie działa, jestem pewien, że można to zrobić znacznie łatwiej. Żadne inne, prostsze rozwiązanie, które wymyśliłem, nie powiodło się, np. z powodu usunięcia typu.

Byłbym wdzięczny za pomoc w tej sprawie. Dzięki!

Odpowiedz

2

Coś podobnego do rozwiązania, ale bez pustki *.

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); } 
}; 

Następnie

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

Dzięki. Unikanie pustej wskazówki może być nieco bardziej eleganckie. Szukałem jednak czegoś bardziej zwartego, może bez klas konwersji lub odwiedzin. – DonDieselkopf

+0

To nie będzie całkowicie wykonalne. Czy masz obsługę C++ 11? –

+0

Tak, robię. Jeśli istnieje rozwiązanie C++ 11, byłbym ciekawy. Właściwie oczekiwałem jakiegoś rozwiązania podobnego do CRTP. Ale patrząc na moją aplikację, coraz bardziej kuszę się, by trzymać się wzorca gości. Niemniej jednak wszelkie inne opinie są bardzo mile widziane. – DonDieselkopf