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

Force calling base class virtual function down long chains

本文关键字:基类 虚拟 函数 调用      更新时间:2023-10-16

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

这是我的代码:

////////// 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++中可能吗?

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

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

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

#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函数这一事实或多或少地迫使他们生成类的实例,并阻止他们在构造函数之外进行渲染工作(这将破坏目的)。

如果无论派生版本如何,都希望执行ImageView::render()的操作,为什么不创建一个私有的非虚拟ImageView::base_render(),并在派生render()之前或之后从ImageView::Render()调用它?

Decorator模式在这里可能会有所帮助,但这并不是您想要的。