如何为可覆盖的方法提供默认实现?

时间:2014-05-19 12:30:22

标签: c++ inheritance design-patterns override abstract-class

我正在使用访问者模式,我有以下编译代码:

class DerivedVisitee;

class Visitor
{
public:
    void visit(DerivedVisitee &v);
};

class Visitee
{
public:
    virtual void accept(Visitor &v) = 0;
};

class DerivedVisitee : public Visitee
{
public:
    void accept(Visitor &v) { v.visit(*this); }
};

我想为visit的所有后代提供默认的Visitee方法。因此,我尝试执行以下操作:

class DerivedVisitee;

class Visitor
{
public:
    void visit(DerivedVisitee &v);
};

class Visitee
{
public:
    virtual void accept(Visitor &v) { v.visit(*this); } // added implementation here
};

class DerivedVisitee : public Visitee
{
    // removed overridden method
};

但编译因'void Visitor::visit(DerivedVisitee &)' : cannot convert argument 1 from 'Visitee' to 'DerivedVisitee &'(MSVC)而失败。你能解释一下为什么会发生这种情况,以及做我想做的事情的正确方法是什么?

编辑: Visitor::visit只需要处理DerivedVisitee个对象;换句话说,我打算对Visitor::visit的不同后代使用多个重载的Visitee方法和不同的实现。

2 个答案:

答案 0 :(得分:1)

基本答案是:你不能在纯面向对象的代码中。

本质上,访问者模式是关于传递给visit派生类型,而Visitee表示类型是未知的(它是运行时属性)。


在C ++中,存在一种名为CRTP的模式:

template <typename Derived, typename Base>
class VisiteeHelper: public Base {
public:
    virtual void accept(Visitor& v) override {
        Derived& d = static_cast<Derived&>(*this);
        v.visit(d);
}; // class VisiteeHelper

然后你可以从中得出:

// And there we see the "Curiously Recurring" part:
class DerivedVisitee: public VisiteeHelper<DerivedVisitee, Visitee> {
}; // class DerivedVisitee

class MoreDerivedVisitee: public VisiteeHelper<MoreDerivedVisitee, DerivedVisitee> {
}; // MoreDerivedVisitee

由您决定是否更喜欢简单的样板或智能(但可能令人困惑)的CRTP解决方案。

就个人而言,除非你有多个accept的重载(通过在const-ness上重载最多4个),我不会打扰。手工编写accept的工作量很大,而且很简单,也很容易理解。

答案 1 :(得分:0)

您应该将Visitee&而不是DerivedVisitee&作为visit方法的参数传递。这是使用公共继承多态性的重点。任何派生的对象都可以在需要 base 对象的地方使用。在运行时,将扣除实际类型,并在该对象上调用适当的方法。