1

相关问题:链接

在上述问题的一个答案中,建议我使用访问者模式来解决我的类继承结构的一些问题。但是,我不确定是否可以在我的上下文中使用它,因为我的派生类可以是非类型模板。

为了展示这个问题,我使用了来自以下来源的修改代码:http: //sourcemaking.com/design_patterns/visitor/cpp/2。下面的示例无法编译,因为无法定义虚拟模板方法。但是,我相信,代码展示了我想要实现的目标。该问题是否有任何替代解决方案?

// 1. Add an accept(Visitor) method to the "element" hierarchy
class Element
{
  public:
    virtual void accept(class Visitor &v) = 0;
};

template <unsigned int N>
class This: public Element
{
  public:
     /*virtual*/void accept(Visitor &v);
    string thiss()
    {
        return "This";
    }
};

class That: public Element
{
  public:
     /*virtual*/void accept(Visitor &v);
    string that()
    {
        return "That";
    }
};

// 2. Create a "visitor" base class w/ a visit() method for every "element" type
class Visitor
{
  public:
    template<unsigned int N>
    virtual void visit(This<N> *e) = 0;
    virtual void visit(That *e) = 0;

};

 template<unsigned int N>
 /*virtual*/void This<N>::accept(Visitor &v)
{
  v.visit(this);
}

 /*virtual*/void That::accept(Visitor &v)
{
  v.visit(this);
}

// 3. Create a "visitor" derived class for each "operation" to do on "elements"
class UpVisitor: public Visitor
{
     /*virtual*/void visit(This *e)
    {
        cout << "do Up on " + e->thiss() << '\n';
    }
     /*virtual*/void visit(That *e)
    {
        cout << "do Up on " + e->that() << '\n';
    }

};

class DownVisitor: public Visitor
{
     /*virtual*/void visit(This *e)
    {
        cout << "do Down on " + e->thiss() << '\n';
    }
     /*virtual*/void visit(That *e)
    {
        cout << "do Down on " + e->that() << '\n';
    }

}; 

    int main() 
    {

        Element *list[] = 
        {
            new This<3>(), new That()
        };
        UpVisitor up; // 4. Client creates
         DownVisitor down; //    "visitor" objects
         for (int i = 0; i < 2; i++) list[i]->accept(up);
         for (int i = 0; i < 2; i++) list[i]->accept(down);
    }
4

1 回答 1

2

问题是您的Visitor类与派生自Element. 当你扩展你的设计时,这将比现在更妨碍你。您可以通过提供定义可访问对象的所有要求的“目标”类来减少/消除正确的耦合。由于派生类的名称是一个通用属性,因此您也可以将存储和对其的访问权限放入目标类中。

// 1. Define out visitor and destination interfaces
struct Destination
{
    Destination(const std::string& name) : name_(name) {}
    virtual std::string ident() const { return name_; }

    const std::string name_;
};

struct Visitor
{
    virtual void visit(Destination *e) = 0;
};

这使访问者的要求与 Element 类分开,这似乎是您的意图。然后你的ThisThat类继承Destination并提供必要的实现。

// 2. Define our element and it's derived classes
class Element
{
public:
    virtual void accept(class Visitor &v) = 0;
};

template <unsigned int N>
class This: public Element, public Destination
{
public:
    This() : Destination("This") {}
    virtual void accept(Visitor &v)
    {
        v.visit(this);
    }
};

class That: public Element, public Destination
{
public:
    That() : Destination("That") {}
    virtual void accept(Visitor &v)
    {
        v.visit(this);
    }
};

现在您的上下访问者被简化为如下所示

// 3. Create a "visitor" derived class for each "operation" to do on "elements"
class UpVisitor: public Visitor
{
    void visit(Destination *e) {
        cout << "do Up on " + e->ident() << '\n';
    }
};

class DownVisitor: public Visitor
{
    void visit(Destination *e) {
        cout << "do Down on " + e->ident() << '\n';
    }
}; 

虽然我没有在上面的解决方案中更改它,但我建议更改visit为采用引用而不是指针。由于 C++ 没有空引用的概念,这表明它Destination必需的,而指针可以被认为是可选的。

于 2013-05-27T22:48:57.810 回答