【问题标题】:Visitor Implementation: Constant versus Mutable Visitor访问者实现:常量与可变访问者
【发布时间】:2013-12-14 18:55:21
【问题描述】:

鉴于 constant 访问者和 mutable 访问者之间的区别在于,常量访问者中的方法不允许修改访问的对象。

class Integer_Field;
class Boolean_Field;
class Text_Field;

class Visitor_Constant
{
  public:
    virtual void visit(const Integer_Field& f) = 0;
    virtual void visit(const Boolean_Field& f) = 0;
    virtual void visit(const Text_Field& f) = 0;
};

class Visitor_Mutable
{
  public:
    virtual void visit(Integer_Field& f) = 0;
    virtual void visit(Boolean_Field& f) = 0;
    virtual void visit(Text_Field& f) = 0;
};

我想尽量减少对这些访问者的支持。例如,如果我想出一个类Blob_Field,我需要修改这两个类。我更喜欢只需要修改一个类或模板的东西。

当这些父访问者定义了许多类时,维护问题就会出现。这是我想简化维护的主要原因。

我的问题:
(注意:这必须在不使用 C++11 功能的情况下解决,因为我的开发环境不支持 C++11,我不允许此时升级。)

  1. 有没有办法使用template机制来合并两者 (例如提供 'const' 作为模板的参数)?
  2. 如何设置这些访问者,以便我可以通过 Visitor_Constant 到使用 Visitor_Mutable 的方法?

注意:通过父类组合这些类,会使必须实现和维护的访问者方法加倍。

编辑 1:类关系

class Component; // Base class for fields and records.
class Field : public Component; // Base class for all fields
class Record : public Component // Base class for all records
{
  std::vector< boost::shared_ptr<Component> > component_container;
};
class Integer_Field : public Field;
class Boolean_Field : public Field;
class Text_Field : public Field;

编辑 2:字段的合理性
具体处理字段的一种合理性是生成用于创建表的 SQL 语句的情况。
另一种是从数据库表中加载字段。

【问题讨论】:

  • “字段”类有什么关系?
  • @Cheersandhth.-Alf 字段类是记录的组成部分,例如在数据库/表记录中。
  • 暂时先不管const的问题,你可以让每个visit函数对应一个特定的接口。访问者只需要实现它处理的接口(这些接口可能以某种分层方式排列以支持类型的层次结构)。被访问的字段对象然后可以dynamic_cast访问者下到它自己的基本类型对应的接口,如果有这样的接口,就调用它的函数。这集中了显式向下转换。相比之下,您上面的方案不需要任何向下转换,但具有潜在的维护 prblm
  • 我记得,Andrei Alexandrescu 在他的《现代 C++ 设计》一书中对各种访问者模式实现进行了很好的概述和权衡分析。 Loki 库可能支持其中的一些。

标签: c++ inheritance visitor-pattern const-correctness


【解决方案1】:

有没有办法使用template机制将两者合并(比如提供'const'作为模板的参数)?

您可以通过模板模板参数提供它,并保持纯访问者实现通用。我最初是在 C++11 中做到这一点的,但既然你说你没有它,我会用类型列表来代替它。

这是类型列表的实现。

/* Our empty node for our type list. */
class Empty {};

/* Cons for our type list. */
template <typename First_, typename Rest_>
class Cons {
  public:

  /* First type */
  typedef First_ First;

  /* Rest.  */
  typedef Rest_ Rest;

};  // Cons<First_, Rest_>

这是通用的访问者实现。

/* Forward declaration. */
template <template <typename> class Decorator, typename Members>
class VisitorRecur;

/* Base case. */
template <template <typename> class Decorator, typename Member>
class VisitorRecur<Decorator, Cons<Member, Empty> > {
  public:

  /* Pure virtual for each of the members. */
  virtual void operator()(
      typename Decorator<Member>::Type that) const = 0;

};  // VisitorRecur<Decorator, Member>

/* Recursive case. */
template <template <typename> class Decorator, typename Members>
class VisitorRecur
    : public VisitorRecur<Decorator, typename Members::Rest> {
  public:

  /* Bring the operator()s into scope. */
  using VisitorRecur<Decorator, typename Members::Rest>::operator();

  /* Pure virtual for each of the members. */
  virtual void operator()(
      typename Decorator<typename Members::First>::Type that) const = 0;

};  // VisitorRecur<Decorator, typename Members::Rest>

/* Final visitor. */
template <template <typename> class Decorator, typename Members>
class Visitor : public VisitorRecur<Decorator, Members> {
  public:

  /* Bring the operator()s into scope. */
  using VisitorRecur<Decorator, Members>::operator();

};  // Visitor<Decorator, Members>

这是我们将定义的两个装饰器。

/* ConstRef. */
template <typename T>
class ConstRef {
  public:

  typedef const T & Type;

};  // ConstRef<T>

/* Ref. */
template <typename T>
class Ref {
  public:

  typedef T & Type;

};  // Ref<T>

这是它的用例。

/* Forward declarations. */
class Circle;
class Square;
class Triangle;

/* Add the members into a type list. */
typedef Cons<Circle, Cons<Square, Cons<Triangle, Empty> > > Members;

/* Our const visitor which accepts the members by const-ref. */
typedef Visitor<ConstRef, Members> ConstVisitor;

/* Our mutating visitor which accepts the members by ref. */
typedef Visitor<Ref, Members> MutatingVisitor;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-13
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 2019-03-05
    相关资源
    最近更新 更多