0

My problem extends this problem with longer inheritance chains

This is my code:

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

Actual Output:

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

Required Output:

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

I'm trying to keep just one Base class public method that should call all virtual methods chain. Is something like this possible in C++?

Community
  • 1
  • 1
chunkyguy
  • 3,509
  • 1
  • 29
  • 34

4 Answers4

3

Per this question (Can I call a base class's virtual function if I'm overriding it?), change your definitions like so:

class Sprite : public ImageView{
public:
protected:
    void render(){
        ImageView::render(); // this calls the superclass' virtual method
        std::cout << "Sprite:render" << std::endl;
    }
};
Community
  • 1
  • 1
Wug
  • 12,956
  • 4
  • 34
  • 54
  • Actually, that is the thing I'm trying to avoid. I know might sound crazy, but I just want to know if it's possible to achieve the result without explicitly calling superclass's methods? – chunkyguy Jun 20 '13 at 15:15
  • It isn't, you must do it explicitly. You could force this behavior by calling each method from `Render()` but this doesn't really avoid the problem, just moves it somewhere else. – Wug Jun 20 '13 at 15:15
  • Ah! OK, thanks! I'll will keep watching for answers some more time, then I'll mark this answer as correct :) – chunkyguy Jun 20 '13 at 15:18
  • `s/superclass/base class/`, `s/method/member function/`... someone's got proper C++ terminology to learn. – Griwes Jun 20 '13 at 16:21
  • Every language calls them something different. Sub- and super- are complementary prefixes. Java calls member functions methods. I use a lot of languages, it's hard to keep track. At least you'll never hear me say 'Accessor' or 'Mutator'. – Wug Jun 20 '13 at 16:23
1

I've gone through and implemented what you want using nested class constructors. It's fairly ugly and has rather a lot of boilerplate, but I believe it does exactly what you want.

#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;
}

Strictly speaking, I still don't think there's a way to force people to do it correctly, but with this approach, calling any renderer will automatically call all of the renderers below it (there is no way around this). A clever subclasser is still free to write his own Render subclass without deriving it from the Render class above it, but then he won't get all of that rendering behavior for free, so I think this does as close to what you want as is possible.

The rendering is done entirely in the constructors for the ---Render nested classes, taking advantage of the fact that chaining is always performed for constructors. The user needs only to supply a protected virtual function MakeRender which returns a renderer reference of the required type. The fact that the user only declares the MakeRender function more or less forces them to produce an instance of the class, and keeps them from doing render work outside of the constructor (which would defeat the purpose).

Wug
  • 12,956
  • 4
  • 34
  • 54
  • @sid please review this, I'd like your feedback. – Wug Jun 20 '13 at 16:01
  • This seems like achieving exactly what I was trying to achieve. Though the solution isn't as smooth as I was expecting, but it's good to know that C++ has a solution for my problem. Trust in C++ restored – chunkyguy Jun 20 '13 at 16:14
  • I'm posting my version of your approach, twisted to fit my exact needs, just for reference http://pastebin.com/usdYr6dV – chunkyguy Jun 20 '13 at 16:37
0

If you want the actions of ImageView::render() to be taken no matter what the derived version says, why not create a private, non-virtual ImageView::base_render() and call it from ImageView::Render() before or after the derived render()?

Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • `ImageView::Render()` isn't real, that method is declared in `View`. Let's pretend that it did exist. This will always call `ImageView::render()`, but won't call any intermediate `render()`s if they exist. Say there was a subclass of `Sprite`, `AwesomeSprite`. `ImageView::Render` would thus call `ImageView::base_render()`, which would call `ImageView::render()`. Then it would call `render()`, which resolves to `AwesomeSprite::render()`, skipping `Sprite::render()`. You might be able to find a way to make it work with constructors (which do chain like this) but not with ordinary methods. – Wug Jun 20 '13 at 15:32
  • I was trying to figure out a way where the Render() is only available as public method in View class, and all the derived classes just magically call all the methods up the inheritance chain. But I now realize, that maybe it's not possible with C++, (or with any language) :) – chunkyguy Jun 20 '13 at 15:32
  • The whole point of inheritance is to be able to selectively override behavior, so there's no way to force it to happen in any implementation of any language I can think of (except for constructors, which do chain this way). – Wug Jun 20 '13 at 15:33
  • Seriously, just compile the non-virtual inheritance pattern with the template method pattern and you should be good to go. – Sebastian Redl Jun 20 '13 at 15:38
  • I guess you're suggesting something like this http://pastebin.com/08ySYBrT It solves the problem, but I was exploring some wild thing with C++, where I don't have to remember calling base class's method explicitly. – chunkyguy Jun 20 '13 at 15:41
  • Wait, I missed that you have two levels of inheritance here, which is annoying. You could still do it, but it would require you to rename the function at every inheritance level, which is a horrible API. So yeah, I think you're stuck. – Sebastian Redl Jun 20 '13 at 15:43
0

Decorator pattern could help here but again that's not precisely what you are looking for.

rockoder
  • 747
  • 11
  • 23