views:

159

answers:

6
+4  A: 

This might be a situation where the template pattern (not to be confused with C++ templates) comes in handy. The public Render in the abstract class should be non-virtual, but have it call a private virtual function (e.g. DoRender). Then in the derived classes, you override DoRender instead.

Here's an article that goes into great depth describing the use of template pattern with private virtual functions.

Edit:

I started to put together an example of what I meant, and it seems like there's actually a broader flaw in the architecture. Your use of AbstractRenderer is somewhat frivolous since you're forcing each geometricalobject to be intimately aware of a particular renderer type.

Either the renderer should be able to work off the public methods of Renderables, or Renderables should be able to work off the public methods of the Renderer. Or perhaps you can give the concrete renderers a Renderable factory if there really needs to be such an intimate connection. I'm sure there are some other patterns that would fit well, too.

Cogwheel - Matthew Orlando
The problem is that I'm still limited to the `Render` method interface, like I can't have separate renderables have `Render(AbstractRenderer*...)` and `Render(DirectxRenderer*...)` methods. Or do I miss something?
HardCoder1986
@HardCoder1986: Can you give us an example of how you expect to call Render() ? Will you have this: **[ DirectXGeometricalObject *dxgo = new ...; dxgo.Render(directx_renderer) ]**If the compiler knows at compile time exactly what type is being passed into Render, then I think we can find some way to do what you want.
Aaron McDaid
A: 

Use a setter to set the renderer var and cast it to the proper type in that one place.

Gary
Could you explain, please?
HardCoder1986
wouldn't virtual overriding it still work if you changed the function signature to:virtual void Render(DirectxRenderer* renderer)?
Gary
I guess you mean *override*.
Job
I think I mean overriding the virtual, and overloading the parameter type.
Gary
@Gary This won't work. You can't "downcast" the parameter in the function declaration. Also, C++ treats `virtual void Render(AbstractRenderer* r)` and `virtual void Render(DirectxRenderer* r)` as two separate methods.
Kotti
@Kotti, yea I think you're right. I was just an untested suggestion. But the setter thing would do what he wants. This is why we have to define separate methods in an abstract class when we're doing a visitor pattern.
Gary
+2  A: 

I don't see what your code wants to achieve. You derive Renderable objects to DirectXRenderables and OpenGLRenderables and then provide OpenGL or DirectX functionality in something derived from Renderer. A specific thing uses another specific thing so to speak. It would seem much more reasonable to identify general rendering functions, make them pure virtual members of your abstract renderer and implement them in DirectXRenderer and OpenGLRenderer. Then a IRenderable would have a member function draw roughly like this:

void draw(const AbstractRenderer& r) {
  //general stuff
  r.drawLine(...);
  //only possible on directX
  if(DirectxRenderer rx = dynamic_cast<DirectxRenderer*>(r)) {
  //...
  } else {
    //throw exception or do fallback rendering in case we use something else
  }
} 
pmr
A: 

See if the Bridge design pattern helps you: "Decouple an abstraction from its implementation so that the two can vary independently." In your example, AbstractGeometricalObject would point to an implementation, a pure virtual interface with platform-specific subclasses. The tricky part is taking the time to discover that interface.

Jon Reid
+1  A: 

Using templates, you could split the IRendable into two classes, one for each of the two renderer types. This is probably not the best answer, but it does avoid the need for the dynamic cast:

template <typename RendererType>
struct IRenderable {
    virtual void Render(RendererType* renderer) const = 0;
}

template <typename RendererType>
class AbstractGeometricalObject : public IRenderable<RendererType> {
    virtual void Render(RendererType* renderer) const { ... }
};

class DirectxGeometricalObject : public AbstractGeometricalObject<DirectxRenderer> {
  // this class will now require a void Render(DirectxRenderer* renderer)
}
Aaron McDaid
A: 

Let's distance from compilers and consider theory. If DirectxGeometricalObject::Render expects DirectxRenderer as parameter and not any AbstractRenderer, then some other OtherGeometricalObject::Render will probably expect OtherRenderer object as parameter.

So, different implementations of AbstractGeometricalObject have different signatures of their Render methods. If they are different, then there is no purpose in defining the virtual AbstractGeometricalObject::Render.

If you declare AbstractGeometricalObject::Render(AbstractRenderer*), then you should be able to pass any renderer to any geometrical object. In your case, you can't because dynamic_cast would fail.

zvonimir