I have the following problem in application architecture and am willing to solve it (sorry for a lot of text).
I am building a game engine prototype and I have base abstract class AbstractRenderer (I will use C++ syntax, but still the problem is general).
Assume there are some derived implementations of this renderer, let's say DirectxRenderer and OpenglRenderer.
Now, let's say that only one of these renderers (let's stick to DirectX-based) has a member called IDirect3D9Device* m_device; Obviously at this point everything is fine - m_device is used internally in DirectxRenderer and shouldn't be exposed in the abstract AbstractRenderer superclass.
I also add some abstract rendering interface, for instance IRenderable. It means simply one pure virtual method virtual void Render(AbstractRenderer* renderer) const = 0;
And this is the place where some problems start. Assume I am modelling some scene, so, this scene will probably have some geometrical objects in it.
I create abstract superclass AbstractGeometricalObject and derived DirectX-based implementation DirectxGeometricalObject. The second one would be responsible for storing pointers to DirectX-specific vertex & index buffers.
Now - the problem.
AbstractGeometricalObject should obviously derive the IRenderable interface, because it's renderable in logical terms.
If I derive my DirectxGeometricalObject from AbstractGeometricalObject, the first one should have virtual void Render(AbstractRenderer* renderer) const { ... } method in it, and that Abstract... stuff brings some troubles.
See the code for better explanation:
And for now my classes look the following way:
class AbstractGeometricalObject : public IRenderable {
virtual void Render(AbstractRenderer* renderer) const { ... }
};
class DirectxGeometricalObject : public AbstractGeometricalObject {
virtual void Render(AbstractRenderer* renderer) const {
// I think it's ok to assume that in 99 / 100 cases the renderer
// would be a valid DirectxRenderer object
// Assume that rendering a DirectxGeometricalObject requires
// the renderer to be a DirectxRenderer, but not an AbstractRenderer
// (it could utilize some DX-specific settings, class members, etc
// This means that I would have to ***downcast*** here and this seems really
// bad to me, because it means that this architecture sucks
renderer = dynamic_cast<DirectxRenderer*>(renderer);
// Use the DirectX capabilities, that's can't be taken out
// to the AbstractRenderer superclass
renderer.DirectxSpecificFoo(...);
}
I know I'm probably worrying too much, but this downcast in such a simple case means that I could be forced to make lots of downcasts if my application grows.
Definitely, I would like to avoid this, so please, could you advice me something better in design terms / point out my errors.
Thank you
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.
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
}
}
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)
}
Use a setter to set the renderer var and cast it to the proper type in that one place.
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.
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.
Related
If sb. can change the title to something more understandable I'd be very thankful
This is my current implementation:
std::vector<Zone<sf::CircleShape>*> allZones;
std::vector<Zone<sf::CircleShape>*> estates = initializer->initVillageEstates();
std::vector<Zone<sf::CircleShape>*> communityAreas = initializer->initCommunityAreas();
I'd love to have something like this:
std::vector<Zone<sf::Shape>*> allZones;
std::vector<Zone<sf::CircleShape>*> estates = initializer->initVillageEstates();
std::vector<Zone<sf::RectangleShape>*> communityAreas = initializer->initCommunityAreas();
Where CircleShape and RectangleShape derive from the base class Shape. I think that would be possible for a vector if this would be like the generic type for the vector and not the generic type of the generic type of the vector.
One solution that comes in mind is that I make Zone not a template class but like ZoneShape and ZoneCircle : public ZoneShape, ZoneRectangle : public ZoneShape.
That way I could to something like this:
std::vector<ZoneShape*> allZones;
std::vector<ZoneCircle*> estates = initializer->initVillageEstates();
std::vector<ZoneRectangle*> communityAreas = initializer->initCommunityAreas();
I think that would work but I kinda found the template way more clean for my purpose. So I have to figure out how this might work with that.
To answer your overall question, there's no C++ way to automatically make templates follow the inheritance rules of their type parameters (some other languages like Scala will let you do this, but they're also generally not working with value types). As far as C++ is concerned, a vector of type A is a completely separate type from a vector of type B, even though they're both descended from the same template.
It sounds like you realize that, though. As far as alternatives go, making separate ZoneShape classes for every single shape you might want to hypothetically add is tedious (and violates DRY), so let's not do that. But if plain old templates don't support inheritance the way you want, and making more class inheritance is too repetitive, you could make use of a bit of both worlds:
class ZoneShape {
// Not sure what your Zone class needs to do,
// but include your functionality based on the
// base Shape class here.
public:
virtual void setShape(Shape* shape) = 0;
virtual Shape* getShape() = 0;
};
template<typename T>
class Zone : public ZoneShape {
protected:
// Implemented versions of the base type.
void setShape(Shape* shape) override;
Shape* getShape() override;
public:
// Specific to your specific type.
void setShape(T* t);
T* getSpecificShape(); // EDIT: This was originally "T* getShape()",
// which cannot be overloaded.
};
std::vector<ZoneShape*> allZones;
std::vector<Zone<sf::CircleShape>*> estates = initializer->initVillageEstates();
std::vector<Zone<sf::RectangleShape>*> communityAreas = initializer->initCommunityAreas();
It's not perfect (e.g. a Zone<SquareShape>* cannot necessarily stack with a Zone<RectangleShape>*), but it should allow you to have both generic containers for zones of all shape types as well as more specialized containers for specific shapes.
In a Qt project in C++, I am writing an interface for dynamically loaded plugins using QtPlugin. This interface should allow plugins to register their different parameters, and while a plugin is loaded the main program should display appropriate GUI controls representing each parameter. For instance, a parameter could be an int between 0 and 20 a represented by a QLabel and a QSlider in a box, or a color value represented by a QColorDialog.
Here's the catch: I tried a standard OOP approach (?), having each parameter type inherit an abstract class and creating the GUI representation by implementing a virtual function. This caused a lot of Qt GUI headers to get linked into each plugin file, increasing its size from ~20 KB to ~50 KB.
This isn't about saving those kilobytes but about gaining a better understanding of OOP. I thought about this and tried to find suitable design patterns, then I googled "decoupled polymorphism", "external polymorphism" et c and came across a page that said that this is possible but generally you don't want to go there because it breaks OOP.
So is that it? Either I hide GUI code from the plugin interface and identify each type with an enum or something, and "break OOP", or the class is entirely reponsible for itself but also completely coupled internally?
What solutions would you recommend, if each parameter type consists of a data model, persistence, and GUI controls with signals? What goes where?
EDIT: In other words I'm wondering if the plugins can be pure data and algorithms, unaware of how data controls are created in Qt and independent of Qt GUI headers. It might use Q_OBJECT for signals though.
I'd suggest letting the plugin worry about the types of its arguments, and have a separate component which knows how to map each type onto a GUI control.
This is almost a straight model/view decomposition, so seems like a well-understood idiom.
Now, your type model can be enumerated, or you can use the arguably more OO Visitor pattern, but you're still essentially coming up with a fixed and not-really-extensible type system ahead of time. Is that adequate?
You'll probably end up with some type that knows both the specific derived type of a given argument, and the details of how to render it in Qt. This would handle the Qt signals, and pass values back to the argument.
... Through attempting a dynamic_cast or reading some kind of identification code such as an enum, I'm thinking. I still don't see how the Visitor DP could be used instead of these ...
The Visitor pattern is specifically used to avoid dynamic_cast, so I'm not sure what the confusion is here. Admittedly there's a post-hoc version which does use dynamic_cast, but that's hidden away in the implementation and isn't the usual case anyway.
So, for a concrete example, let's create a model with a couple of argument types:
struct ArgumentHandler; // visitor
class Argument { // base class for visitable concrete types
public:
virtual void visit(ArgumentHandler&) = 0;
};
// sample concrete types
class IntegerArgument: public Argument {
int value_;
public:
IntegerArgument(int value = 0) : value_(value) {}
void set(int v) { value_ = v; }
int get() const { return value_; }
virtual void visit(ArgumentHandler&);
};
class BoundedIntegerArgument: public IntegerArgument
{
int min_, max_;
public:
virtual void visit(ArgumentHandler&);
// etc...
};
Now we have some concrete types for it to visit, we can write the abstract visitor
struct ArgumentHandler {
virtual ~ArgumentHandler() {}
virtual void handleInteger(IntegerArgument&);
virtual void handleBoundedInteger(BoundedIntegerArgument&);
// ...
};
and our concrete types implement visitation like so:
void IntegerArgument::visit(ArgumentHandler& handler) {
hander.handleInteger(*this);
}
void BoundedIntegerArgument::visit(ArgumentHandler& handler) {
hander.handleBoundedInteger(*this);
}
Now, we can write an abstract plugin only in terms of the data model types - it doesn't need to know anything about the GUI toolkit. Let's say we just provide a way to query its arguments for now (note that each concrete subtype should have set/get methods)
class PluginBase
{
public:
virtual int arg_count() const = 0;
virtual Argument& arg(int n) = 0;
};
Finally, we can sketch a View that knows how to interrogate an abstract plugin for its arguments, how to display each concrete argument type, and how handle inputs:
// concrete renderer
class QtView: public ArgumentHandler
{
struct Control {};
struct IntegerSpinBox: public Control {
QSpinBox control_;
IntegerArgument &model_;
};
struct IntegerSlider: public Control {
QSlider control_;
BoundedIntegerArgument &model_;
};
std::vector<std::unique_ptr<Control>> controls_;
public:
// these overloads know how to render each argument type
virtual void handleInteger(IntegerArgument &arg) {
controls_.push_back(new IntegerSpinBox(arg));
}
virtual void handleBoundedInteger(BoundedIntegerArgument &arg) {
controls_.push_back(new IntegerSlider(arg));
}
// and this is how we invoke them:
explicit QtView(PluginBase &plugin) {
for (int i=0; i < plugin.arg_count(); ++i) {
plugin.arg(i).visit(*this);
}
}
};
I've omitted all the virtual destructors, the Qt signal handling, and lots more. But, hopefully you can see how a QtView::IntegerSpinBox object could handle the valueChanged signal from its captive spinbox widget, and call model_.set() to push that back to the plugin.
You can send message of any type, to anywhere and catch it on the other side with anything with templatious virtual packs which were made exactly for loose-coupling-with-anything purpose.
If I understood you correctly, you should rethink the behaviour. Instead of having the module registering everything (which can be really a lot) in the main app, you could create a base class for a module specific renderer, and a factory in each module, that instantiates the concrete renderer for the module. You then can ask the module to render the information you are providing to the module.
I am designing some classes for my project in C++ at the moment but I got a problem.
I want to create a camera class which holds all the needed values (e.g. transformation matrices) but the function which renders the camera should be exchangeable. This sounds like a usual case for the strategy pattern. Thus I created an interface which defines the render-function and gave the the camera class a pointer to this interface.
The problem is that the render function needs access to all the data in the camera class and therefore I gave this function a pointer to the camera class as a parameter. It looks like this:
#include "ICameraRender.h"
class Camera{
private:
ICameraRender* _cameraRender;
public:
Camera();
Camera(ICameraRender& cameraRender);
~Camera();
void renderCamera(){ _cameraRender->render(this); }
void setCameraRender(ICameraRender& cameraRender);
/..../
};
class ICameraRender{
public:
virtual ~ICameraRender(){
}
//Override me
virtual void render(Camera* camera) = 0;
};
This doesn't seem to be an elegant solution due to the liability to an infity loop (calling camera->renderCamera() in the render-function in ICameraRender). Is there a better solution to this problem?
Regards
EDIT:
I came up with another solution. Since the function which operates on the camera's data, only needs access to the data I thought I could split up the camera class itself. A class called Camera and CameraModel. The last one holds all the needed data and the first one does operations on it.
Therefore I just have to pass a pointer to CameraModel to my function:
class CameraModel{
private:
/...data.../
public:
/...setter and getter.../
};
class Camera{
private:
CameraModel* _cameraModel;
ICameraRender* _cameraRender;
public:
Camera();
Camera(ICameraRender& cameraRender);
~Camera();
void renderCamera(){ _cameraRender->render(_cameraModel); }
void setCameraRender(ICameraRender& cameraRender);
/..../
};
class ICameraRender{
public:
virtual ~ICameraRender(){
}
//Override me
virtual void render(CameraModel* cameraModel) = 0;
};
Now the render-function (which only calculates new values for the camera according to user input) does no longer have access to the renderCamera-function.
What do you think about this solution?
Regards Stan
You're right, it does seem like a bad design. :)
I don't see why a camera render needs access to a camera. I'm sure you can pass something else as parameter. The render doesn't need access to all the camera members, so you can just pass the ones it needs (and, if there's a lot of them, wrap them in a structure CameraConfig or something like that).
If the different renders need different parameters, you can make a separate hierarchy with ICameraConfig.
This is probably a great time to use Policy-based design to implement the strategy pattern, especially since you're using C++ and you're probably targeting a compiler older than 2002. (Since C++'s templating mechanism is so awesome, we can get the strategy pattern for free this way!)
First: Make your class accept the strategy/policy class (in this case, your ICameraRenderer) at a template parameter. Then, specify that you are using a certain method from that template parameter. Make calls to that method in the camera class...
Then implement your strategies as a plain old class with a render() method!
This will look something like this:
class Camera<RenderStrategy>{
using RenderStrategy::render;
/// bla bla bla
public:
void renderCamera(){ render(cameraModel); }
};
class SpiffyRender{
public:
void render(CameraModel orWhateverTheParameterIs){ // some implementation goes somewhere }
};
Whenever you want to make a camera that uses one of those policy/strategies:
// the syntax will be a bit different, my C++ chops are rusty;
// in general: you'll construct a camera object, passing in the strategy to the template parameter
auto SpiffyCamera = new Camera<SpiffyRender>();
(Since your renderer strategy doesn't have any state, that makes this approach even more favorable)
If you are changing your renderer all the time, then this pattern / approach becomes less favorable... but if you have a camera that always renders the same way, this is a slightly nicer approach. If your renderer has state, you can still use this method; but you'll want a reference to the instance inside the class, and you won't use the Using:: statement. (In general, with this, you write less boilerplate, don't need to make any assignments or allocations at runtime, and the compiler works for you)
For more about this,see: http://en.wikipedia.org/wiki/Policy-based_design
Or read Modern C++ Design... it's a great read, anyways! http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315
As an unrelated aside: You may want to look into some of the goodness that C++x11 gives you. It'll really clean up your code and make it safer. (Especially the shared/unique/etc ptr classes.)
I am working on a Ray Tracing task, here is the problematic source:
class Geometry
{
public:
virtual RayTask *intersectionTest(const Ray &ray) = 0;
};
class Sphere : public Geometry
{
public:
RayTask *intersectionTest(const Ray &ray);
};
class BoundingVolume
{
public:
virtual bool intersectionTest(const Ray &ray) = 0;
};
class BoundingSphere : public Sphere, BoundingVolume
{
public:
bool intersectionTest(const Ray &ray) // I want this to be inherited from BoundingVolume
{
return Sphere::intersectionTest(ray) != NULL; // use method in Sphere
}
};
source above can not compile, error information:
error: conflicting return type specified for ‘virtual bool BoundingSphere::intersectionTest(const Ray&)’
error: overriding ‘virtual RayTask Sphere::intersectionTest(const Ray&)
I want to implement BoundingSphere::intersectionTest using method in Sphere, so I need to inherit from both BoundingVolume and Sphere. but due to inherit functions that has the same parameter list with different return type, things messed up...
I do not want to duplicate codes with the same functionality...
could any one give me a solution?...
The compiler is attempting to override two virtual methods with different return types, which isn't allowed: how would the compiler know how much memory to allocate for a function call if it doesn't know what the return type will be? The two methods cannot have the same names; try changing one to a more suitable meaning.
If you feel that these names best represent the meanings of the actions they both provide (which I'm not sure of), I would also suggest that you consider your hierarchies carefully. Is a spherical BoundingVolume really a Sphere? Perhaps not: it's implemented in terms of Sphere (private inheritance, doesn't solve your problem), or it has a Sphere (composition, would solve your problem in this simple case). The latter case, though, might present problems for move complex classes, where you want a BoundingSphere to have all the methods of Sphere. Or, perhaps, do you need to differentiate between BoundingVolumes and normal Geometrys?
Another solution to the problem would be to use non-member functions for one of these hierarchies, with Koenig lookup (the type of the argument) calling the proper version. I can't say without really knowing what your hierarchies look like. But do consider your design: if you have the same-named operation giving you back completely different semantic results, is the operation properly named/designed?
I am working on game engine prototype and have the following question:
Right now my engine implementation is DirectX-bound and everything works fine.
I've got a core::Renderer class which has methods to render geometry, set shaders, lightning, etc...
Some of them are templated, some not.
class Renderer {
// ...
template <typename Geometry> RenderGeometry(shared_ptr<Geometry> geometry);
};
Let's say I want to extend the flexibility of my engine and I wan't it to work using DirectX and OpenGL. As I understand it right now, the idea is to take everything interface-specific to the base core::Renderer class, make all those calls virtual and then provide their DirectX-specific and OpenGL-specific implementation.
If my geometrical object wasn't a template, everything would look better:
class Renderer {
virtual void RenderGeometry(shared_ptr<core::Non_template_Geometry> geometry);
};
class DXRenderer {
// Here goes our custom implementation
// for DirectX-based geometry rendering
virtual void RenderGeometry(...)
};
// The same for OpenGL
The problem with the first (initial variant) is that virtual functions are not allowed to be templated.
So here comes the question - how should I solve it?
Any hacks / tricks / patterns for this situation or for template virtual functions emulation?
Use a base Geometry class:
class Geometry {
public:
virtual ~Geometry() { }
virtual void Render() = 0;
};
and have each of your Geometry-type classes derive from this base class and implement their specific rendering functionality by overriding Render.
Then, Renderer::RenderGeometry does not need to be a function template; it can simply take a pointer to the base Geometry class and call the virtual function Render.
Template is not neccessity. If you think hard about it, most of the time templates only do text-replacing and is a safer macros.
OOP was not design to rely heavily on templates, but composition and inheritance (like what James suggested)