2013-06-20 49 views
5

我將數據存儲在從文件讀入的C++樹形結構中。該樹看起來像這樣:在樹形轉換中合併模板和繼承

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

樹建成後,我想轉換它,到一個字符串。

爲了保持樹代碼轉換代碼是分開的,我想用模板,即實現類似的東西:

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

然而,由於樹節點存儲爲BaseNode*,我不不知道如何訪問這樣的模板成員函數。由於模板成員函數不能被繼承,所以我認爲這不會起作用。

我沒有拿出一個有效的解決方案,但:

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

和轉換邏輯可完全獨立:

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

測試代碼:

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

回報預期結果:

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

雖然這個解決方案有效,但我相信它可以更容易地完成。我提出的任何其他更簡單的解決方案都失敗了,例如由於類型擦除。

我將不勝感激任何幫助。謝謝!

回答

2

類似於您的解決方案但沒有void *的東西。

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

然後

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

感謝。避免void指針可能稍微更優雅。然而,我正在尋找更緊湊的東西,也許沒有轉換或訪問類。 – DonDieselkopf

+0

這不會完全可行。你有C++ 11支持嗎? –

+0

是的,我喜歡。如果有C++ 11解決方案,我會很好奇。我實際上期待着一些類似CRTP的解決方案。但看着我的應用程序,我越來越傾向於堅持使用訪問者模式。不過,任何其他意見都非常受歡迎。 – DonDieselkopf