你能覆盖同一个类中的纯虚函数吗?

时间:2017-08-07 18:57:08

标签: c++ c++11 inheritance override virtual-method

我想扩展一个带有虚函数的抽象基类,并将函数名称保持为虚拟,但是在"可能"之前和之后运行代码。被覆盖的儿童功能。

以下是一个例子:

我有一个可以绘制的基类(接口):

class IDraw {
    public:
        virtual void do_draw(Screen *scr) = 0;
};

我希望将此接口保留在子类中并能够覆盖它, 例如,我有一个游戏类,它清理屏幕,绘制东西,然后翻转显示缓冲区:

class Game : public IDraw {
    public:
        // Keep the interface
        // This can be overridden by sub classes
        virtual void do_draw(Screen *scr) = 0; // (1)
    private:
        // But override the base class so if s.b. calls
        // do_draw from a IDraw pointer it executes this!
        void IDraw::do_draw(Screen *scr) override; // (2)
};

// Implementation of (2)
void Game::IDraw::do_draw(Screen *scr) {
    // Do stuff before like clear the screen
    scr->clear();
    // Call the method supplied by childs
    this->do_draw(scr); // (1)
    // Present the drawing
    scr->present();
}

由于我在子项提供的函数之前和之后都有代码,因此我不能简单地覆盖保持虚拟,因为孩子必须决定是在之前还是之后调用Game :: do_draw()//(2)。

我知道我可以简单地用不同的名称调用函数(2),但由于我需要很多类来做这种事情,所以它会以相同概念的大量名称结束。

在C ++ 11中有没有办法做这类事情?

1 个答案:

答案 0 :(得分:2)

  

我希望将此接口保留在子类中并能够覆盖它,

自动情况已经如此,因为您在public访问级别继承了它。

  

例如我有一个游戏类,它可以清理屏幕,绘制内容而不是翻转显示缓冲区...
  ...   有没有办法在C ++ 11中做这种事情?

完全独立于任何c ++ 11特性,只需编写一个抽象函数声明的实现,并添加一个额外的间接层(又名Template Method Pattern):

class Game : public IDraw {
public:
    // Keep the interface
    // This can be overridden by sub classes
    void do_draw(Screen *scr) override {
         OnPreDraw(scr);
         OnDraw(scr);
         OnPostDraw(scr);
    }
protected:
    virtual void OnPreDraw(Screen *scr) {
       // Default implementation
       scr->clear();
    }
    virtual void OnDraw(Screen *scr) = 0; // << Class is still abstract
    virtual void OnPostDraw(Screen *scr) {
       // Default implementation
       scr->present();
    }
};

这将允许在更精细的操作序列中注入Game的任何实现,但保持基类实现的默认行为。
此外,基类仍然是抽象的,并且有效地强制任何派生类实现OnDraw(),这实际上与do_draw()相同。

  

但是因为我需要很多班级做这种事情,所以它会以相同概念的大量名字结束。

没有。至于你的概念只涉及操作

 OnPreDraw(scr);
 OnDraw(scr);
 OnPostDraw(scr);

在那个序列中,将来不再对整个类继承层次结构进行更改。

延伸:

您也可以使用Mixin pattern 1

执行此操作
template<typename Derived>
class AbstractIDrawImpl : public IDraw {
    void do_draw(Screen *scr) override {
         static_cast<Derived*>(this)->OnPreDraw(scr);
         static_cast<Derived*>(this)->OnDraw(scr);
         static_cast<Derived*>(this)->OnPostDraw(scr);
    }

    // Expects public implementations
    void OnPreDraw(Screen *scr) {
       // Default implementation
       scr->clear();
    }
    // Just no default implementation for 
    //    void OnDraw(Screen *scr) << Class is still abstract
    void OnPostDraw(Screen *scr) {
       // Default implementation
       scr->present();
    }
};

上面的mixin示例可以绑定到IDraw的任何实现,为publicOnPreDraw()OnDraw()提供OnPostDraw()函数:

class MyGame : public AbstractIDrawImpl<MyGame> {
public:
    // IDraw interface implementation
    void OnPreDraw(Screen *scr) {
        // Call base class implementation
        AbstractIDrawImpl<MyGame>::OnPreDraw(scr);
        // E.g fill my background here
    }
    void OnDraw(Screen *scr) {
        // For each game entity call 
        // IDraw::do_draw(scr);
        for(auto drawableEntity : drawableEntities_) {
            drawableEntity->do_draw(scr);
        }
    }
    // Skip implementation of OnPostDraw()
private:
    std::vector<std::shared_ptr<IDraw>> drawableEntities_;
};

1)
Alexei Andrescou的Policy based design paradigm很好地描述了这种模式,并与Microsoft's ATL大量使用。