Force calling base class virtual function down long chains
我的问题用更长的继承链扩展了这个问题
这是我的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | ////////// 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; } |
实际产量:
1 2 3 4 5 6 | .. Draw ImageView ... View::Render ImageView:render ... Draw Sprite ... View::Render Sprite:render |
所需输出:
1 2 3 4 5 6 7 | .. Draw ImageView ... View::Render ImageView:render ... Draw Sprite ... View::Render ImageView:render Sprite:render |
我试图只保留一个应该调用所有虚拟方法链的基类公共方法。C++中有可能这样吗?
根据这个问题(如果我重写一个基类的虚函数,我可以调用它吗?),更改定义如下:
1 2 3 4 5 6 7 8 | class Sprite : public ImageView{ public: protected: void render(){ ImageView::render(); // this calls the superclass' virtual method std::cout <<"Sprite:render" << std::endl; } }; |
我已经使用嵌套类构造函数完成并实现了您想要的。它相当难看,有相当多的样板,但我相信它完全符合你的要求。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | #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; } |
严格地说,我仍然认为没有一种方法可以强迫人们正确地进行渲染,但是使用这种方法,调用任何渲染器都会自动调用它下面的所有渲染器(这是不可能的)。一个聪明的子类仍然可以自由地编写自己的呈现子类,而不必从上面的呈现类派生它,但是这样他就不能免费获得所有的呈现行为,所以我认为这尽可能接近你想要的。
渲染完全是在
装饰图案可以在这里有所帮助,但这又不是你想要的。
如果你想让