0

我的问题用更长的继承链扩展了这个问题

这是我的代码:

////////// 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

4 回答 4

3

根据这个问题(如果我要覆盖它,我可以调用基类的虚函数吗?),更改您的定义,如下所示:

class Sprite : public ImageView{
public:
protected:
    void render(){
        ImageView::render(); // this calls the superclass' virtual method
        std::cout << "Sprite:render" << std::endl;
    }
};
于 2013-06-20T15:09:54.647 回答
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用户仅或多或少地声明函数这一事实迫使他们生成类的实例,并阻止他们在构造函数之外进行渲染工作(这会破坏目的)。

于 2013-06-20T15:58:50.707 回答
0

装饰器模式在这里可能会有所帮助,但这又不是您要寻找的。

于 2013-06-20T15:56:59.630 回答
0

如果您希望ImageView::render()无论派生版本怎么说都采取行动,为什么不创建一个私有的、非虚拟的并在派生之前或之后ImageView::base_render()调用它呢?ImageView::Render()render()

于 2013-06-20T15:18:28.200 回答