在树转换中结合模板和继承

Combining templates and inheritance in tree conversion

本文关键字:继承 结合 转换      更新时间:2023-10-16

我有数据存储在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 ...

虽然这个解决方案有效,但我相信它可以更容易地完成。我想到的任何其他更简单的解决方案都失败了,例如,由于类型擦除。

我将感谢任何帮助。谢谢!

类似于您的解决方案,但没有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;
}