强制调用基类虚函数向下长链

时间:2013-06-20 15:01:09

标签: c++

我的问题是使用更长的继承链扩展this problem

这是我的代码:

////////// View ///////////////
class View{
public:
    void Render(){
        std::cout << "View::Render" << std::endl;
        render();
    }
protected:
    virtual void render() = 0;
};
////////// ImageView ///////////////
class ImageView : public View{
public:
protected:
    void render(){
        std::cout << "ImageView:render" << std::endl;
    }
};
////////// Sprite ///////////////
class Sprite : public ImageView{
public:
protected:
    void render(){
        std::cout << "Sprite:render" << std::endl;
    }
};
////////// Utility ///////////////
void Draw(View *vw){
    vw->Render();
}
////////// main ///////////////
int main(){
    std::cout << "... Draw ImageView ..." << std::endl;
    ImageView *imgvw = new ImageView;
    Draw(imgvw);
    delete imgvw;

    std::cout << "... Draw Sprite ..." << std::endl;
    Sprite *sp = new Sprite;
    Draw(sp);
    delete sp;

    return 0;
}

实际输出:

.. Draw ImageView ...
View::Render
ImageView:render
... Draw Sprite ...
View::Render
Sprite:render

必需输出:

.. Draw ImageView ...
View::Render
ImageView:render
... Draw Sprite ...
View::Render
ImageView:render
Sprite:render

我正在尝试只保留一个应该调用所有虚拟方法链的基类公共方法。 这样的事情在C ++中是可能的吗?

4 个答案:

答案 0 :(得分:3)

this question (Can I call a base class's virtual function if I'm overriding it?),更改您的定义:

class Sprite : public ImageView{
public:
protected:
    void render(){
        ImageView::render(); // this calls the superclass' virtual method
        std::cout << "Sprite:render" << std::endl;
    }
};

答案 1 :(得分:1)

我已经完成并使用嵌套类构造函数实现了您想要的内容。它相当丑陋并且有相当多的样板,但我相信它完全符合您的要求。

#include <string>
#include <iostream>

using namespace std;

class View
{
protected:
    class ViewRender
    {
    public:
        ViewRender(const View &v) 
        {
            cout << "ViewRender:constructor" << endl;
        }
    };

    // returns a reference to a temporary.  I'm not sure how to avoid doing this
    // the reference isn't actually used, and we can't pass it a reference to one
    // and have it populate it since the trick is in the constructor.

    virtual ViewRender &MakeRender() = 0;
public:
    void Render() { MakeRender(); }
};

class ImageView : public View
{
protected:
    class ImageViewRender : public View::ViewRender
    {
    public:
        ImageViewRender(const View &v) : ViewRender(v)
        {
            cout << "ImageViewRender:constructor" << endl;
        }
    };

    virtual ImageViewRender &MakeRender() { return ImageViewRender(*this); }
};

class Sprite : public ImageView
{
protected:
    class SpriteRender : public ImageView::ImageViewRender
    {
    public:
        SpriteRender(const View &v) : ImageViewRender(v)
        {
            cout << "SpriteRender:constructor" << endl;
        }
    };

    virtual SpriteRender &MakeRender() { return SpriteRender(*this); }
};

class AwesomeSprite : public Sprite
{
protected:
    class AwesomeSpriteRender : public Sprite::SpriteRender
    {
    public:
        AwesomeSpriteRender(const View &v) : SpriteRender(v)
        {
            cout << "AwesomeSpriteRender:constructor" << endl;
        }
    };

    virtual AwesomeSpriteRender &MakeRender() { return AwesomeSpriteRender(*this); }
};

int main()
{
    AwesomeSprite as;
    ImageView &iv = as;

    cout << "rendering AwesomeSprite..." << endl;
    as.Render();

    cout << "rendering Awesome (downcast to ImageView)..." << endl;
    iv.Render();

    system("pause");
    return 0;
}

严格来说,我仍然认为强制人们没有办法正确地做到这一点,但是通过这种方法,调用任何渲染器都会自动调用它下面的所有渲染器(有没办法这个)。一个聪明的子类仍然可以自由编写自己的Render子类而不从它上面的Render类派生它,但是他不会免费获得所有的渲染行为,所以我认为这与你想要的一样接近可能的。

渲染完全在---Render嵌套类的构造函数中完成,利用链接总是为构造函数执行的事实。用户只需提供受保护的虚拟函数MakeRender,它返回所需类型的渲染器引用。事实上,用户只是或多或少地声明MakeRender函数强制它们生成类的实例,并阻止它们在构造函数之外进行渲染工作(这会破坏目的)。

答案 2 :(得分:0)

如果您希望无论衍生版本说明什么都采取ImageView::render()的操作,为什么不创建私有的非虚拟ImageView::base_render()并在ImageView::Render()之前调用它在派生render()之后?

答案 3 :(得分:0)

装饰者模式可以在这里提供帮助,但这又不是你想要的。