2017-08-07 92 views
2

我想用一个虚函数扩展一个抽象基类,并将函数名称保持为虚拟,但在“可能”重写的子函数之前和之后运行代码。你可以重写同一个类中的纯虚函数吗?

下面是一个例子:

我对事物的基类(接口),可以得出:

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

不可以。您不能用不同的名称覆盖功能。 – SergeyA

回答

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

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(); 
    } 
}; 

上述混入例如可以绑定到的IDraw任何实现,它提供public功能为OnPreDraw(),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)
即图案是公用克塞Andrescou的Policy based design paradigm描述和Microsoft's ATL大量使用。

+1

这就是我最终使用的,但我想知道是否有一种方法可以避免许多函数名称为相同的事情,因为它不会是相同的扩展IDraw或游戏,因此,如果我决定更改为游戏父项我必须照顾改变覆盖名称相应 – DarioDF

+0

@DarioDF那么,这是做AFAIK的最佳模式。另一种选择可能是进入CRTP和静态多态/ mixins的方向。我怀疑这是值得的。这种模式很好地满足了你的需求,并且为派生类增加了另一个间接级别。 – user0042

+0

@DarioDF我已经扩展了我的答案。 – user0042

相关问题