C ++访问者模式和多态性

时间:2016-08-07 06:01:28

标签: c++ polymorphism abstract-class virtual-functions

以下代码是我在项目中实现的VisitorPattern的简化版本。

#include <iostream>
class AVisitor {
public:
    virtual void visit(class A *) = 0;
};

class ExtendedVisitor : public AVisitor {
public:
    virtual void visit(class B *) = 0;
};

class A {
public:
    virtual void accept(AVisitor *visitor) {
        std::cout << "Call accept of A" << std::endl;
        visitor->visit(this);
    }
};

class B : public A {
public:
    void accept(AVisitor *visitor) override {
        std::cout << "Call accept of B" << std::endl;
        B *just_this = this;
        visitor->visit(just_this);  //why this calls to visit(A*)
        visitor->visit((B*) just_this); //useless casting 
    }
};

class ActualVisitor : public ExtendedVisitor {
public:
    void visit(A *x) override {
        std::cout << "Call visit on A*" << std::endl;
    }
    void visit(B *x) override {
        std::cout << "Never called" << std::endl;
    }
};

int main() {
    ActualVisitor visitor;
    A *a = new B();
    a->accept(&visitor);
}

我不明白为什么B类的accept方法调用访问者(A *)方法而不是访问者(B *)。主要功能打印

Call accept of B
Call visit on A*
Call visit on A*

相反,以下代码的行为符合我的预期:

#include <iostream>

class AVisitor {
public:
    virtual void visit(class A *) = 0;
    virtual void visit(class B *) = 0;
};

class A {
public:
    virtual void accept(AVisitor *visitor) {
        std::cout << "Call accept of A" << std::endl;
        visitor->visit(this);
   }
};

class B : public A {
public:
    void accept(AVisitor *visitor) override {
        std::cout << "Call accept of B" << std::endl;
        B *just_this = this;
        visitor->visit(just_this);  //now it works
        visitor->visit((B*) just_this);  
    }
};

class ActualVisitor : public AVisitor {
public:
    void visit(A *x) override {
        std::cout << "Call visit on A*" << std::endl;
    }
    void visit(B *x) override {
        std::cout << "Call visit on B*" << std::endl;
    }
};

int main() {
    ActualVisitor visitor;
    A *a = new B();
    a->accept(&visitor);
}

现在打印:

Call accept of B
Call visit on B*
Call visit on B*

然后问题似乎是AVisitor类的继承。我想知道为什么会发生这种情况以及设置带有“专门”访问者的VisitorPattern的正确方法(此处ExtendedVisitor也可以访问B对象)

2 个答案:

答案 0 :(得分:1)

您的B::accept具有以下签名:

void accept(AVisitor *visitor) override;

所以,让我们检查一下AVisitor的界面。它有

virtual void visit(class A *) = 0;

这就是它的全部(在你的第一个版本中)。确实ExtendedVisitor

virtual void visit(class B *) = 0;

但是不会覆盖AVisitor中的方法。事实上,您的第二个版本可以帮助您了解原因。由于

virtual void visit(class A *) = 0;
virtual void visit(class B *) = 0;

可以一起存在于同一个类中(它们是第二个版本中的重载),然后它们就是这方面的不同方法。

答案 1 :(得分:0)

您正在错误地实施访问者。这是正确的方法:

private ImageView iv;
private Button btn;
int i = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    btn = (Button) findViewById(R.id.btn);
    iv = (ImageView) findViewById(R.id.iv);

    btn.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick(View v) {
            if(i>3){
                i=i%3;
            }
            ObjectAnimator  oa2= ObjectAnimator.ofFloat(iv, "rotation", i*90,(i+1)*90);
            oa2.setDuration(1000);
            oa2.start();
            i++;
        }
    });
}

然后

class AVisitor {
public:
    virtual void visit(class A *) = 0;
    virtual void visit(class B *) = 0;
    // virtual void visit(class C *) = 0; etc
    // a separate function for every class in your hierarchy
};

不需要class ActualVisitor : public Visitor ...

ExtendedVisitor必须了解层次结构中的每个类。这是这种模式的主要缺点。