我的问题是使用更长的继承链扩展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 ++中是可能的吗?
答案 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)
装饰者模式可以在这里提供帮助,但这又不是你想要的。